状压DP复习

深感自己姿势水平之蒻……一直都不是很会状压DP,NOIP又特别喜欢考,就来复习一发……

题目来源 Orz sqzmz

T1 【BZOJ4197】【NOI2015】寿司晚宴

(做过)质因数分解最大的质因子独自处理,$\sqrt{500}$以内的质数只有八个,因此可以用$2^{16}$的状态来表示一种方案;

然后有同样因子的两个数不能同时出现,排序然后随便搞搞就行了……

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long ll;
 8 const int p[8]={2,3,5,7,11,13,17,19};
 9 struct num{
10     int n,bigp;
11 }a[501];
12 bool cmp(num a,num b){
13     return a.bigp<b.bigp;
14 }
15 int n,r=256;
16 ll mod,ans,f[256][256],g[2][256][256];
17 int main(){
18     scanf("%d%lld",&n,&mod);
19     for(int i=2;i<=n;i++){
20         int tmp=i;
21         for(int j=0;j<8;j++){
22             if(!(tmp%p[j])){
23                 a[i].n|=(1<<j);
24                 while(!(tmp%p[j]))tmp/=p[j];
25             }
26         }
27         a[i].bigp=tmp;
28     }
29     sort(a+2,a+n+1,cmp);
30     f[0][0]=1;
31     for(int i=2;i<=n;i++){
32         if(i==2||a[i].bigp!=a[i-1].bigp||a[i].bigp==1){
33             memcpy(g[0],f,sizeof(g[0]));
34             memcpy(g[1],f,sizeof(g[1]));
35         }
36         for(int j=r-1;~j;j--){
37             for(int k=r-1;~k;k--){
38                 if((j&k)>0)continue;
39                 if(!(a[i].n&k))g[0][a[i].n|j][k]=(g[0][a[i].n|j][k]+g[0][j][k])%mod;
40                 if(!(a[i].n&j))g[1][j][a[i].n|k]=(g[1][j][a[i].n|k]+g[1][j][k])%mod;
41             }
42         }
43         if(i==n||a[i].bigp!=a[i+1].bigp||a[i].bigp==1){
44             for(int j=r-1;~j;j--){
45                 for(int k=r-1;~k;k--){
46                     if((j&k)>0)continue;
47                     f[j][k]=g[0][j][k]+g[1][j][k]-f[j][k];
48                 }
49             } 
50         }
51     }
52     for(int j=r-1;~j;j--){
53         for(int k=r-1;~k;k--){
54             if((j&k)>0)continue;
55             ans=(ans+f[j][k])%mod;
56         }
57     }
58     ans=(ans+mod)%mod;
59     printf("%lld",ans);
60     return 0;
61 }

猜你喜欢

转载自www.cnblogs.com/dcdcbigbig/p/9853036.html