HDU4623 CRIME 【状压DP】【同类项合并】
题目大意:
求相邻元素互质的排列个数。
题目分析:
由于互质只与质因数有关,所以我们对于质因数种类相同的数合并为一类,特殊的,1,17,19,23是一类,因为没有数与他们不互质。
那么我们做各个位进制不同的状压DP。转移就是在末尾添加哪个数。
代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<iostream> 7 using namespace std; 8 9 #define P __gcd 10 11 int n,mod; 12 int tot,res,maxx; 13 14 int GCD[30][30]; 15 int a[14]; 16 //1,2,3,5,2*3,7,2*5,11,13,2*7,3*5,3*7,2*11,2*13 17 int bel[30]={0,0,1,2,1,3,4,5,1,2,6,7,4,8,9,10,1,0,4,0,6,11,12,0,4,3,13,2,9}; 18 int data[14]={1,2,3,5,6,7,10,11,13,14,15,21,22,26}; 19 int sum[14]; 20 int fac[6]={1,1,2,6,24,120}; 21 22 int f[1800000][14]; 23 24 void GetSubSet(){ 25 memset(a,0,sizeof(a));maxx=0; 26 for(int i=1;i<=n;i++) a[bel[i]]++,maxx=max(maxx,bel[i]); 27 sum[0] = 1; 28 for(int i=1;i<=maxx;i++) sum[i] = sum[i-1]*a[i-1]+sum[i-1]; 29 } 30 31 vector<int> v[29]; 32 void dfs(int now,int dd,int num){ 33 if(now > maxx){ 34 v[num].push_back(dd); 35 }else{ 36 for(int i=0;i<=a[now];i++){ 37 dfs(now+1,dd+i*sum[now],num+i); 38 } 39 } 40 } 41 42 int nw[15]; 43 void work(){ 44 for(int i=0;i<=maxx;i++) f[sum[i]][i] = 1; 45 for(int i=0;i<=n;i++) v[i].clear(); 46 dfs(0,0,0); 47 for(int i=1;i<n;i++){ 48 for(int j=0;j<v[i].size();j++){ 49 int p=v[i][j]; 50 for(int k=maxx;k>=0;k--){nw[k] = p/sum[k];p%=sum[k];} 51 p = v[i][j]; 52 for(int k=0;k<=maxx;k++){ 53 if(nw[k] == 0 || f[p][k]==0) continue; 54 for(int l=0;l<=maxx;l++){ 55 if(a[l]-nw[l] == 0||GCD[l][k]!=1) continue; 56 f[p+sum[l]][l] += f[p][k]; 57 f[p+sum[l]][l] %= mod; 58 } 59 } 60 } 61 } 62 int ans = 0; 63 for(int i=0;i<=maxx;i++) ans = (ans+f[v[n][0]][i])%mod; 64 for(int i=0;i<=maxx;i++) 65 ans=(ans*fac[a[i]])%mod; 66 printf("%d\n",ans); 67 } 68 69 int main(){ 70 int t; scanf("%d",&t); 71 for(int i=0;i<14;i++)for(int j=0;j<14;j++)GCD[i][j]=P(data[i],data[j]); 72 while(t--){ 73 scanf("%d%d",&n,&mod); 74 memset(f,0,sizeof(f)); 75 GetSubSet(); 76 work(); 77 } 78 return 0; 79 }