BZOJ 2580 video game
这个题目是老师添加到我们学校的oj上的,估计数据是改过了的吧。题意大概是给了n个串,让你构造出来一个长度不超过k的串,使得这n个串在构造出来的这个串中出现次数最大。这也是我的ac自动机+dp第一题。虽然理解的还不是那么透,但还是做出来了,之前因为dp数组开的过小,wa了好多遍。感觉dp跟ac自动机结合在一起,dp也不显得那么难了。
ac代码:
View Code
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> #include <stack> #include <map> #include <set> using namespace std; const int maxn=25; const int maxnum=1010; char s[maxn][maxn]; int dp[maxnum][maxnum],n,k,line; struct node { int cnt; int index; node *fail; node *next[3]; }memory[1000000]; node *que[maxnum]; node *createnode() { node *p=&memory[line]; for(int i=0;i<3;i++) p->next[i]=NULL; p->cnt=0; p->fail=NULL; p->index=line++; return p; } class AC { public : node *root; AC() { root=NULL; } void insert(char *str) { int len=strlen(str); if(!root) root=createnode(); node *loca=root; for(int i=0;i<len;i++) { int num=str[i]-'A'; if(loca->next[num]==NULL) loca->next[num]=createnode(); loca=loca->next[num]; } loca->cnt++; } void build() { std::queue<node *>s; while(!s.empty()) s.pop(); s.push(root); root->fail=NULL; while(!s.empty()) { node *loca=s.front(); s.pop(); for(int i=0;i<3;i++) { if(loca->next[i]!=NULL) { if(loca==root) loca->next[i]->fail=root; else { node *tmp=loca->fail; while(tmp!=NULL) { if(tmp->next[i]!=NULL) { loca->next[i]->fail=tmp->next[i]; break; } tmp=tmp->fail; } if(tmp==NULL) loca->next[i]->fail=root; } if(loca->next[i]->fail->cnt) loca->next[i]->cnt+=loca->next[i]->fail->cnt; s.push(loca->next[i]); } else if(loca==root) loca->next[i]=root; else loca->next[i]=loca->fail->next[i]; } } } int DP() { memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int i=0;i<k;i++) { for(int j=0;j<line;j++) { if(dp[i][j]==-1) continue; for(int idx=0;idx<3;idx++) { if(memory[j].next[idx]==NULL) continue; int num=memory[j].next[idx]->index; if(dp[i][j]+memory[num].cnt>dp[i+1][num]) dp[i+1][num]=dp[i][j]+memory[num].cnt; } } } int ans=0; for(int i=0;i<=k;i++) { for(int j=0;j<line;j++) ans=max(ans,dp[i][j]); } return ans; } }; void data_in() { AC ac; memset(s,0,sizeof(s)); line=0; for(int i=0;i<n;i++) { scanf("%s",s[i]); ac.insert(s[i]); } ac.build(); printf("%d\n",ac.DP()); memset(s,0,sizeof(s)); } int main() { while(~scanf("%d %d",&n,&k)) { data_in(); } return 0; }
之后会陆续放上这一类的题目。
勸君惜取少年時&莫待無花空折枝
posted on 2012-11-20 20:40 Raining Days 阅读(167) 评论(0) 编辑 收藏 举报