zoj 3535 Gao the String II(AC自动机+DP)
来源:互联网 发布:淘宝售假申诉包成功 编辑:程序博客网 时间:2024/05/01 23:56
题意:给出两个字符串集合A,B,现在每次可以在集合A中挑一个字符串接在当前组成的串S后(可以重叠),对于每个长度不超过L的S串,S中每出现一个B中的串,那么这个串的价值加一,求串的最大的价值。
思路:把B插入Trie建立AC自动机。然后进行dp,dp[i][j][k]表示长度为i的串,最后接的一个串是j,此时状态为k时串的最大价值,然后对于每个状态,枚举一下能接下去的串就行了,注意接上去的串要至少让长度增加一,另外如果覆盖了上一个串,实际上这是没有意义的,所以不用考虑。本来以为复杂度会很高,但实际上没有那么糟糕。还有,给出的B的串有可能重复,这里要注意一下。
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<stack>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=555;const int csize=26;int ch[maxn][csize],lastv[maxn],flag[maxn];int next[maxn],cnt[maxn],size;char str[maxn],astr[55][15];int m,n,L,dp[55][55][maxn],conect[55][55][15],lena[55];void Init(){ memset(ch[0],0,sizeof(ch[0])); memset(cnt,0,sizeof(cnt)); memset(lastv,0,sizeof(lastv)); memset(flag,0,sizeof(flag)); memset(next,0,sizeof(next)); size=0;}void Insert(const char *s){ int u=0; for(int i=0;s[i];++i) { int c=s[i]-'a'; if(!ch[u][c]) { ch[u][c]=++size; memset(ch[size],0,sizeof(ch[size])); } u=ch[u][c]; } flag[u]++;}void build(){ queue<int>q; for(int i=0;i<csize;++i) if(ch[0][i]) q.push(ch[0][i]); int r,u; while(!q.empty()) { r=q.front();q.pop(); for(int c=0;c<csize;++c) { u=ch[r][c]; if(!u) {ch[r][c]=ch[next[r]][c];continue;} q.push(u); int j=next[r]; while(j&&!ch[j][c]) j=next[j]; next[u]=ch[j][c]; lastv[u]=flag[next[u]]?next[u]:lastv[next[u]]; } } for(int i=1;i<=size;++i) { u=i; if(flag[u]||lastv[u]) { u=flag[u]?u:lastv[u]; while(u) { cnt[i]+=flag[u]; u=lastv[u]; } } }}bool check(int x,int y,int z){ int lenx=lena[x]; if(z>lenx) return false; for(int i=0;i<z;++i) { if(astr[x][lenx-z+i]!=astr[y][i]) return false; } return true;}int solve(){ lena[0]=0; memset(conect,0,sizeof(conect)); for(int i=1;i<=m;++i) { conect[0][i][0]=1,conect[0][i][1]=0; lena[i]=strlen(astr[i]); } for(int i=1;i<=m;++i) for(int j=1;j<=m;++j) { conect[i][j][0]=1; conect[i][j][1]=0; for(int k=1;k<lena[j];++k) { if(check(i,j,k)) {conect[i][j][0]++;conect[i][j][conect[i][j][0]]=k;} } } memset(dp,0xff,sizeof(dp)); dp[0][0][0]=0; int ans=0,u,c,tmp; for(int i=0;i<=L;++i) for(int j=0;j<=m;++j) for(int k=0;k<=size;++k) { if(j==0&&i!=0) continue; if(dp[i][j][k]==-1) continue; if(dp[i][j][k]>ans) ans=dp[i][j][k]; for(int x=1;x<=m;++x) for(int y=1;y<=conect[j][x][0];++y) { u=k;tmp=0; for(int z=conect[j][x][y];astr[x][z];++z) { c=astr[x][z]-'a'; u=ch[u][c]; tmp+=cnt[u]; } int pos=i+lena[x]-conect[j][x][y]; if(pos>L) continue; if(dp[pos][x][u]==-1) dp[pos][x][u]=dp[i][j][k]+tmp; else dp[pos][x][u]=max(dp[pos][x][u],dp[i][j][k]+tmp); } } return ans;}int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(~scanf("%d%d%d",&m,&n,&L)) { Init(); astr[0][0]='\0'; for(int i=1;i<=m;++i) scanf("%s",astr[i]); for(int i=0;i<n;++i) { scanf("%s",str); Insert(str); } build(); int ans=solve(); printf("%d\n",ans); } return 0;}
0 0
- zoj 3535 Gao the String II(ac自动机+dp)
- zoj 3535 Gao the String II(AC自动机+DP)
- Zoj 3535 Gao the String II (AC自动机+dp)
- zoj 3535 Gao the String II (ac自动机+dp)
- ZOJ 3535 Gao the String II
- zoj 3228 Searching the String【ac自动机】
- ZOJ 3228 Searching the String(AC自动机)
- ZOJ 3228 Searching the String(AC自动机)
- zoj -- 3228 Searching the String(AC自动机)
- ZOJ - 3228 Searching the String (AC自动机)
- [AC自动机] zoj Searching the String
- zoj 3228 Searching the String(AC自动机)
- ZOJ 3228 Searching the String AC自动机
- zoj 3228 Searching the String (ac自动机)
- zoj 3228 Searching the String 【AC自动机】
- ZOJ 3228 Searching the String(AC自动机)
- ZOJ 3648 Gao the Grid II
- Zoj 3545 Rescue the Rabbit(ac自动机+dp)
- 组成原理——输入输出技术
- 什么是静态(static)?什么是静态方法,静态变量,静态块和静态类?
- C中字符串常见操作
- 实战Linux Bluetooth编程(一) 协议栈概述
- 第五讲 ASP.NET系统对象和状态管理(四)
- zoj 3535 Gao the String II(AC自动机+DP)
- 【Linux之路】进程与线程(实验)
- POJ 1003
- Protel常用操作
- css 自定义全局的input样式(提交按钮,文本框)
- MyEclipse中修改项目运行地址栏中项目名称
- Servlet——初识Servlet
- 避免Java应用中NullPointerException的技巧和最佳实践
- MFC创建快捷菜单(右键菜单)