标签:
题意:中文的题目,意思就是说有很多串,每个串都有权值,权值为999的串必须出现,-999的串必须不出现。权值在-999~999之间。
然后必须出现的串不超过8个。然后给一个全为小写目标串,问最少需要删除多少个字母才能够保证必须出现的串都出现,次数一样保证权值最大。输出次数和权值。
然后根据样例,那些必须出现的串,其实权值是0。
思路:
很明显一开始建自动机构成trie图,但是需要注意的就是mark和sum的更新。个人是把所有中间的节点的sum全部赋值成了-inf。
接着只有8个必须出现的串,所以必须要状压一下。
所以最后就是dp[i][j][k][l],处理了i个字母,在j这个节点,k这个状态。l=0代表这个字母不删,l=1代表这个字母删。
然后是个结构体存两个值次数和评分。然后就是更新的时候有点麻烦。
然后注意一下,最后的评分有可能是负数。
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" #include"map" #include"string" #define inf 999999 using namespace std; struct trie { int mark,id,sum; trie *next[27],*fail; trie() { mark=0; sum=-inf; memset(next,0,sizeof(next)); fail=NULL; } }; trie *root,*node[1700]; int triecont; void init(char *v,int k,int x) { trie *p=root; for(int i=0; v[i]; i++) { int tep=v[i]-'a'; if(p->next[tep]==NULL) { p->next[tep]=new trie(); p->next[tep]->id=triecont; node[triecont++]=p->next[tep]; } p=p->next[tep]; } if(k==1) //必须出现 { p->mark=(1<<x); p->sum=0; } else if(k==-1) p->mark=-1; //必须不出现 else p->sum=x; //无特定要求 } void getac() { queue<trie*>q; q.push(root); while(!q.empty()) { trie *p=q.front(); q.pop(); for(int i=0; i<26; i++) { if(p->next[i]==NULL) { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); if(p!=root) { if(p->next[i]->mark==-1 || p->next[i]->fail->mark==-1) //更新必须不出现 p->next[i]->mark=-1; else { p->next[i]->mark|=p->next[i]->fail->mark; if(p->next[i]->fail->sum!=-inf) //更新权值 { if(p->next[i]->sum==-inf) p->next[i]->sum=0; p->next[i]->sum+=p->next[i]->fail->sum; } } } } } } } struct Dp { int cs,pf; } dp[2][1605][259][2]; //这里必须要滚动,不然MLE int main() { int t,cas=1; cin>>t; while(t--) { triecont=0; root=new trie(); node[triecont]=root; root->id=triecont++; int n,cnt=0; scanf("%d",&n); while(n--) { char x[177]; int y; scanf("%s%d",x,&y); if(y==-999) init(x,-1,0); else if(y==999) init(x,1,cnt++); else init(x,0,y); } getac(); char fuck[123]; scanf("%s",fuck); int len=strlen(fuck); for(int i=0; i<triecont; i++) for(int j=0; j<(1<<cnt); j++) for(int k=0; k<2; k++) { dp[0][i][j][k].cs=inf; dp[0][i][j][k].pf=-inf; } dp[0][0][0][0].cs=dp[0][0][0][1].cs=0; dp[0][0][0][0].pf=dp[0][0][0][1].pf=0; for(int i=1; i<=len; i++) { for(int j=0; j<triecont; j++) for(int k=0; k<(1<<cnt); k++) for(int l=0; l<2; l++) { dp[i%2][j][k][l].cs=inf; dp[i%2][j][k][l].pf=-inf; } for(int j=0; j<triecont; j++) { for(int k=0; k<(1<<cnt); k++) { if(dp[1-i%2][j][k][0].cs==dp[1-i%2][j][k][1].cs && dp[1-i%2][j][k][0].cs==inf) continue; for(int l=0; l<2; l++) { if(node[j]->next[fuck[i-1]-'a']->mark!=-1) //这里需要注意,有的情况是必须删除的,所以不删除的情况是要判断一下的。 { trie *p=node[j]->next[fuck[i-1]-'a']; int tep=p->mark|k; Dp cur=dp[i%2][p->id][tep][0],now; if(dp[1-i%2][j][k][0].cs<dp[1-i%2][j][k][1].cs) now=dp[1-i%2][j][k][0]; else if(dp[1-i%2][j][k][0].cs>dp[1-i%2][j][k][1].cs) now=dp[1-i%2][j][k][1]; else { now.cs=dp[1-i%2][j][k][1].cs; now.pf=max(dp[1-i%2][j][k][0].pf,dp[1-i%2][j][k][1].pf); } if(p->sum!=-inf) { if(now.pf==inf) now.pf=0; now.pf+=p->sum; } if(now.cs<cur.cs) cur=now; else if(now.cs==cur.cs) cur.pf=max(now.pf,cur.pf); dp[i%2][p->id][tep][0]=cur; } Dp cur=dp[i%2][j][k][1],now; //这里是这个位置删除的更新 if(dp[1-i%2][j][k][0].cs<dp[1-i%2][j][k][1].cs) now=dp[1-i%2][j][k][0]; else if(dp[1-i%2][j][k][0].cs>dp[1-i%2][j][k][1].cs) now=dp[1-i%2][j][k][1]; else { now.cs=dp[1-i%2][j][k][1].cs; now.pf=max(dp[1-i%2][j][k][0].pf,dp[1-i%2][j][k][1].pf); } now.cs++; if(now.cs<cur.cs) cur=now; else if(now.cs==cur.cs) cur.pf=max(now.pf,cur.pf); dp[i%2][j][k][1]=cur; } } } } Dp ans; ans.cs=inf; ans.pf=-inf; for(int i=0; i<triecont; i++) { Dp now; if(dp[len%2][i][(1<<cnt)-1][0].cs<dp[len%2][i][(1<<cnt)-1][1].cs) now=dp[len%2][i][(1<<cnt)-1][0]; else if(dp[len%2][i][(1<<cnt)-1][0].cs<dp[len%2][i][(1<<cnt)-1][1].cs) now=dp[len%2][i][(1<<cnt)-1][1]; else { now.cs=dp[len%2][i][(1<<cnt)-1][1].cs; now.pf=max(dp[len%2][i][(1<<cnt)-1][0].pf,dp[len%2][i][(1<<cnt)-1][1].pf); } if(now.cs<ans.cs) ans=now; else if(now.cs==ans.cs) ans.pf=max(now.pf,ans.pf); } printf("Case %d: ",cas++); if(ans.cs==inf) puts("Banned"); else printf("%d %d\n",ans.cs,ans.pf); } return 0; }
[AC自动机+状压dp] hdu 4534 郑厂长系列故事——新闻净化
标签:
原文地址:http://blog.csdn.net/wdcjdtc/article/details/44171253