状压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 }
T2 【BZOJ1879】【SDOI2009】Bill的挑战
设$f[i][s]$表示到第$i$位,匹配状态为$s$的方案数(S为十五位二进制数),预处理转移状态DP即可。
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 #define mod 1000003
10 using namespace std;
11 typedef long long ll;
12 int t,n,k,len,ans,bt[65536],p[51][26],f[51][65536];
13 char s[16][51];
14 int main(){
15 for(int i=1;i<65536;i++)bt[i]=bt[i>>1]+(i&1);
16 scanf("%d",&t);
17 while(t--){
18 memset(f,0,sizeof(f));
19 memset(p,0,sizeof(p));
20 ans=0;
21 scanf("%d%d",&n,&k);
22 for(int i=0;i<n;i++){
23 scanf("%s",s[i]);
24 }
25 len=strlen(s[0]);
26 for(int i=0;i<n;i++){
27 for(int j=0;j<len;j++){
28 if(s[i][j]=='?'){
29 for(int c=0;c<26;c++)p[j][c]|=(1<<i);
30 }else p[j][s[i][j]-'a']|=(1<<i);
31 }
32 }
33 f[0][(1<<n)-1]=1;
34 for(int i=0;i<len;i++){
35 for(int j=1;j<(1<<n);j++){
36 if(f[i][j]){
37 for(int c=0;c<26;c++){
38 f[i+1][j&p[i][c]]=(f[i+1][j&p[i][c]]+f[i][j])%mod;
39 }
40 }
41 }
42 }
43 for(int i=0;i<(1<<n);i++){
44 if(bt[i]==k)ans=(ans+f[len][i])%mod;
45 }
46 printf("%d\n",ans);
47 }
48 return 0;
49 }