Anshan warm-up match, also the original question of multiple schools last year
Question:
Evaluate the number of adjacent numbers in the order of N numbers and perform the modulo operation
The idea at that time was to press DP .. DP [I] [State] State to record whether a certain number is removed in binary format. I indicates the number at the end of the current sequence.
Then GCD status is transferred
But n is 28, and there are hundreds of millions of States .. It cannot be done ..
After I came back, I found that I could use the mathematical method to optimize the problem. So after half a day, I finally got the AC.
First, in this question:
Whether two numbers are mutually correlated is only with their prime factor. Therefore, the numbers with the same prime factor are equivalent, which is called the equivalence class of this problem.
It is easy to find these equivalence classes and obtain the number of classes ..
Therefore, you only need to process these equivalence classes, and then multiply each equivalence class by the number of permutation numbers to get the answer.
However, when there is a quantity, binary compression cannot be used. Hash should be used for compression.
After research, we will find that the hash pressure is similar to the binary pressure, except that the base number is changed from (1 + 1) ^ n to (Num [1] + 1) * (Num [2] + 1 ).... it is also easy to understand.
After processing these statuses, we found that there are only 5600000 states for n = 28, and the number of equivalence classes is 17, so the complexity is 17*5600000.
It's time for MLE. Since the modulo Max is 30000, the array is changed to short, and the intermediate result int is used to prevent overflow, so the memory is no longer exposed.
Then the time limit is 30 s. I thought it was okay, and the result was no longer ..
Then I thought for a while and found that the numbers 17, 19, and 23 are mutually compatible with any other number .. So they are equivalent to 1.
After this optimization, the complexity is reduced to about 14*1800000.
8800 Ms ac...
The Code is as follows:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int prime[]={2,3,5,7,11,13,17,19,23};const int np=9;int state[30];int g[300][300];int vi[300];int num[30];int base[30];short dp[19][2000000];bool ok[29];int n,m,ns,st;void ini(){ scanf("%d%d",&n,&m); memset(g,0,sizeof(g)); memset(vi,0,sizeof(vi)); memset(num,0,sizeof(num)); ns=0; state[++ns]=0; num[ns]=1; for(int i=2;i<=n;i++) { st=0; if(ok[i]) { num[1]++; continue; } for(int j=0;j<np;j++) { if(i%prime[j]==0) { st|=(1<<j); } } if(!vi[st]) { state[++ns]=st; num[ns]=1; vi[st]=ns; } else { num[vi[st]]++; } } for(int i=1;i<=ns;i++) { for(int j=1;j<=ns;j++) { if((state[i]&state[j])==0) g[i][j]=1; } } base[1]=1; st=0; for(int i=1;i<=ns;i++) { base[i+1]=base[i]*(num[i]+1); st+=base[i]*num[i]; }}int getnum(int i,int x){ int res=(x%base[i+1])/(base[i]); return res;}int getstate(int i,int num){ return num*base[i];}void dfs(int t,int x){ if(t==0) { dp[x][0]=1; return ; } if(dp[x][t]!=-1) return; dp[x][t]=0; for(int i=1;i<=ns;i++) { if(g[x][i]&&getnum(i,t)>=1) { dfs(t-base[i],i); dp[x][t]=((int)dp[x][t]+dp[i][t-base[i]])%m; } } return;}int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE int T; scanf("%d",&T); memset(ok,0,sizeof(ok)); ok[17]=1; ok[19]=1; ok[23]=1; while(T--) { ini(); memset(dp,-1,sizeof(dp)); int ans=0; for(int i=1;i<=ns;i++) { dfs(st-base[i],i); ans=((int)ans+dp[i][st-base[i]])%m; } for(int i=1;i<=ns;i++) { while(num[i]>1) { ans=((int)ans*num[i])%m; num[i]--; } } printf("%d\n",ans); }}
Hdu4623: Crime mathematical optimization DP