BZOJ1879 Bill的挑战
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1879
本来是一道水题(~~~~(>_<)~~~~)。
开始SB了,敲了个AC自动机dp,MLE
发现数据中 '?' 好多呀 ~~~~(>_<)~~~~ 空间变$O(len^2)$
然后去想朴素dp,枚举一下那些集合和T匹配,然后$O(n \cdot 2^n)$ dp,又W又T一是爽。
TLE 40:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define c(w,i) ((w>>i)&1) #define mod 1000003 #define LL long long #define MP(x,y) make_pair(x,y) #define fir first #define sec second using namespace std; int n,K,cnt; char S[110][110],T[110]; LL f[110][26]; vector<pair<int,char> > v[110]; LL calc(int w){ for(int i=0;i<n;i++) T[i]='?'; for(int i=0;i<cnt;i++) if(c(w,i)){ for(int j=0;j<n;j++) if(S[i][j]!='?'){ if(T[j]=='?'||T[j]==S[i][j]) T[j]=S[i][j]; else return 0; } } memset(f,0,sizeof(f)); for(int i=0,fl;i<cnt;i++) if(!c(w,i)){ fl=0; for(int j=0;j<n;j++){ if(S[i][j]!='?' && T[j]!='?' && S[i][j]!=T[j]) fl=1; } if(!fl){ for(int j=0;j<n;j++){ if(S[i][j]!='?') v[j].push_back(MP(i,S[i][j])); } } } f[0][0]=1; for(int i=0;i<n;i++){ for(int w=0;w<(1<<cnt);w++) if(f[i][w]){ for(char c='a';c<='z';c++){ if(T[i]!='?'&&T[i]!=c) continue; int now=0; for(int j=v[i].size()-1;~j;j--) if(v[i][j].sec!=c) now|=(1<<v[i][j].fir); f[i+1][now|w]+=f[i][w]; } } } return f[n][((1<<cnt)-1)&~w]; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&cnt,&K); for(int i=0;i<cnt;i++) scanf("%s",S[i]); n=strlen(S[0]); LL ans=0; for(int w=0;w<(1<<cnt);w++){ int tmp=0; for(int i=0;i<cnt;i++) if(c(w,i)) tmp++; if(tmp!=K) continue; ans=(ans+calc(w))%mod; } printf("%lld\n",ans); } return 0; }
然后发现我是SB
没有看完题呀,原来长度都相同。
直接裸dp f[i][S] 表示T的前i位,n个串的匹配状态为S的方案数。
注意因为长度都相同,只能从第一位开始匹配呀!!!
然后水了。
AC 100:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define c(w,i) ((w>>i)&1) #define mod 1000003 using namespace std; int n,K,cnt,f[60][65536],cv[60][26]; char S[20][60]; int main(){ freopen("test.in","r",stdin); int T; scanf("%d",&T); while(T--){ memset(f,0,sizeof(f)); scanf("%d%d",&cnt,&K); for(int i=0;i<cnt;i++) scanf("%s",S[i]); n=strlen(S[0]); for(int i=0;i<n;i++){ for(int t=0;t<26;t++){ cv[i][t]=0; for(int j=0;j<cnt;j++){ if(S[j][i]=='?' ||S[j][i]==t+'a') cv[i][t]|=(1<<j); } } } f[0][(1<<cnt)-1]=1; for(int i=0;i<n;i++) for(int j=0;j<(1<<cnt);j++){ if(f[i][j]){ for(int t=0;t<26;t++) (f[i+1][j&cv[i][t]]+=f[i][j])%=mod; } } int ans=0; for(int w=0;w<(1<<cnt);w++){ int tmp=0; for(int i=0;i<cnt;i++) if(c(w,i)) tmp++; if(tmp==K) (ans+=f[n][w])%=mod; } printf("%d\n",ans); } return 0; }