http://acm.hdu.edu.cn/showproblem.php?pid=4534
自动机+DP(状态压缩)
整体思路应该很明确,但要注意一些细节方面的处理 否则会wa
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<set> #include<vector> #include<stack> #include<queue> using namespace std; const int MOD=1000000007; const int N=110; const int M=1610; const int K=26; struct nodeTrie { int v; int k; int fail; int next[K]; void initialize() { v=0; k=0; fail=-1; memset(next,-1,sizeof(next)); } }trie[M]; int cnt,root; int to[M][K]; char s[K]; char words[N]; int dp1[2][M][1<<8],dp2[2][M][1<<8]; int getNewNode() { ++cnt; trie[cnt].initialize(); return cnt; } void addWord(int p,char *s,int k,int l) { if(s[0]=='\0') return ; for(int i=0;s[i]!='\0';++i) { if(trie[p].next[s[i]-'a']==-1) trie[p].next[s[i]-'a']=getNewNode(); p=trie[p].next[s[i]-'a']; } if(k==999) trie[p].k=(1<<(l-1)); else if(k==-999) trie[p].k=-1; else trie[p].v=k; } int init(int n) { cnt=-1; root=getNewNode(); int l=0; while(n--) { int k; scanf("%s %d",s,&k);//puts(s);cout<<k<<endl; if(k==999) ++l; addWord(root,s,k,l); } return l; } void bfs(int p) { trie[p].fail=root; queue<int>qt; qt.push(p); while(!qt.empty()) { int y; int x=qt.front();qt.pop(); for(int i=0;i<K;++i) if(trie[x].next[i]!=-1) { qt.push(trie[x].next[i]); if(x==root) {trie[trie[x].next[i]].fail=root;continue;} y=trie[x].fail; while(y!=root&&trie[y].next[i]==-1) y=trie[y].fail; if(trie[y].next[i]!=-1) trie[trie[x].next[i]].fail=trie[y].next[i]; else trie[trie[x].next[i]].fail=root; int l=trie[x].next[i],r=trie[trie[x].next[i]].fail; if(trie[l].k==-1||trie[r].k==-1) trie[l].k=-1; else {trie[l].k=(trie[l].k|trie[r].k);trie[l].v+=trie[r].v;} } } } void makeTo(int n,int k) { for(int i=0;i<=n;++i) for(int j=0;j<k;++j) { int p=i; while(p!=root&&trie[p].next[j]==-1) p=trie[p].fail; if(trie[p].next[j]!=-1) to[i][j]=trie[p].next[j]; else to[i][j]=root; } }; int main() { //freopen("data.in","r",stdin); int T; scanf("%d",&T); for(int w=1;w<=T;++w) { int n; scanf("%d",&n); int h=(1<<init(n)); bfs(root); makeTo(cnt,K); scanf("%s",words); int m=strlen(words); memset(dp1,0,sizeof(dp1)); memset(dp2,0,sizeof(dp2)); int M=0,P=0; for(int i=0;i<=m;++i) { for(int j=0;j<=cnt;++j) for(int l=0;l<h;++l) {dp1[(i+1)%2][j][l]=0;dp2[(i+1)%2][j][l]=0;} for(int j=0;j<=cnt;++j) for(int l=0;l<h;++l) { if(dp1[i%2][j][l]==0&&(j>0||l>0)) continue; if(l==(h-1)) { if(M<dp1[i%2][j][l]||(M==dp1[i%2][j][l]&&P<dp2[i%2][j][l])) {M=dp1[i%2][j][l];P=dp2[i%2][j][l];} } if(i==m) continue; int r=to[j][words[i]-'a']; if(dp1[(i+1)%2][j][l]<dp1[i%2][j][l]|| (dp1[(i+1)%2][j][l]==dp1[i%2][j][l]&&dp2[(i+1)%2][j][l]<dp2[i%2][j][l])) {dp1[(i+1)%2][j][l]=dp1[i%2][j][l];dp2[(i+1)%2][j][l]=dp2[i%2][j][l];} if(trie[r].k!=-1) { int k=(l|(trie[r].k)); if(dp1[(i+1)%2][r][k]<dp1[i%2][j][l]+1|| (dp1[(i+1)%2][r][k]==dp1[i%2][j][l]+1&&dp2[(i+1)%2][r][k]<dp2[i%2][j][l]+trie[r].v)) {dp1[(i+1)%2][r][k]=dp1[i%2][j][l]+1;dp2[(i+1)%2][r][k]=dp2[i%2][j][l]+trie[r].v;} } } } printf("Case %d: ",w); if(M==0) printf("Banned\n"); else printf("%d %d\n",m-M,P); } return 0; }