只讲解题方法,不讲题目题意
代码风格为个人喜好,请体谅
bzoj 1879 状态压缩dp -
设g[i][j]表示匹配到i位该位字符选j的集合 设f[i][j]为匹配打i位,集合位j的方案数 枚举每一位的字符得出g[i][j] f[i][j]->f[i+1][j&g[i][ch]] 答案即为 sigma{f[len][set(popcount1==k)]} 复杂度为 o(set*n*len)=o(2^15*15*50)
#include<bits/stdc++.h> using namespace std; const int mod= (int) 1e6 + 3 , N = 52 ; int n,k,ans=0; int g[N][100],f[N][(1<<15)+20],len; char s[20][N]; int count(int x) { int ans=0;for(;x;ans+=(x&1),x>>=1);return ans; } void add(int &x,int y) {x+=y;for(;x>=mod;x-=mod);} main() { int t; for(scanf("%d",&t);t;t--) { memset(g,0,sizeof(g));ans=0;memset(f,0,sizeof(f)); cin>>n>>k; for(int i=0;i<n;i++) scanf("%s",s[i]);len =strlen(s[0]); for(int i=0;i<n;i++) for(int j=‘a‘;j<=‘z‘;j++) for(int l=0;l<len;l++) if(s[i][l]==‘?‘||s[i][l]==j) g[l][j-‘a‘]|=(1<<i); f[0][(1<<n)-1]=1; for(int i=0;i<len;i++) for(int j=0;j<(1<<n);j++) if(f[i][j]) for(int ch=‘a‘;ch<=‘z‘;ch++) add(f[i+1][g[i][ch-‘a‘]&j],f[i][j]); for(int j=0;j<(1<<n);j++) if(count(j)==k) add(ans,f[len][j]); cout<<ans<<"\n"; } }
时间: 2024-10-11 15:58:39