题目大意:
给出一些匹配串,要造一个长度不超过L的字符串,每个匹配串有自己的价值,匹配串每次出现在字符串里都会贡献一次价值...要求可能得到的最大价值。
匹配串总长不超200,L<=10^14,时限6s
典型的倍增floyd...看数据范围大概就知道是什么东西了= =
暴力写法的话..建个AC自动机,每个节点的价值,就是结束节点在它的fail链上的匹配串的价值总和。。 然后在上面暴力DP。f[i][j]表示从i节点开始,往后走j步能得到的最大价值。
这个形式和USACO那道“奶牛接力跑‘一模一样。。。
f[i][j][k]表示从i节点开始,走2^j步,到达k的最大价值。fa[i][j][k]:从k节点开始,走2^j步,能否到达i。
f[i][j][k]=max{ f[i][j-1][k1]+f[k1][j-1][k] },( fa[k1][j-1][i]和fa[k][j-1][k1]为true
求出f后,就和快速幂的姿势一样把L拆成若干个二的次幂之和,然后把对应的各个f数组并起来(记为g)。
最后的答案就是max{ g[0][i] },(i为自动机上的节点。
时间复杂度O(n^3*logL)..CF测评姬挺快的。。只跑了1200+ms。。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #define ll long long 7 #define ull unsigned long long 8 #define d double 9 using namespace std; 10 const int maxn=203; 11 const ll inf=(1ll<<62)-1ll; 12 int ch[maxn][26],next[maxn][26],tot; 13 int dl[maxn],fail[maxn],val[maxn],v[maxn]; 14 ll f[maxn][61][maxn],g[maxn][2][maxn]; 15 bitset<maxn>fa[maxn][61]; 16 char s[maxn]; 17 18 int i,j,k,n,m,now,pre; 19 ll L; 20 bool first=1; 21 22 23 int ra,fh;char rx; 24 inline int read(){ 25 rx=getchar(),ra=0,fh=1; 26 while(rx!='-'&&(rx<'0'||rx>'9'))rx=getchar(); 27 if(rx=='-')fh=-1,rx=getchar(); 28 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh; 29 } 30 inline void upd(ll &a,ll b){if(a<b)a=b;} 31 32 void trie(int n,int v){ 33 int p=0; 34 for(int i=1;i<=n;i++){ 35 s[i]-='a'; 36 if(!ch[p][s[i]])ch[p][s[i]]=++tot,p=tot; 37 else p=ch[p][s[i]]; 38 } 39 val[p]+=v;//printf(" ggpos:%d ",p); 40 } 41 void getfail(){ 42 int l=0,r=1,i,now,j,p;dl[1]=0; 43 while(l<r){ 44 now=dl[++l]; 45 for(i=0;i<26;i++)if(ch[now][i]){ 46 j=ch[now][i],dl[++r]=j,next[now][i]=j; 47 for(p=fail[now];p&&!ch[p][i];p=fail[p]); 48 if(!now)fail[j]=0;else fail[j]=ch[p][i]; 49 val[j]+=val[fail[j]];//printf(" %d - - - ->%d val:%d ",j,fail[j],val[j]); 50 }else{ 51 for(p=fail[now];p&&!ch[p][i];p=fail[p]); 52 next[now][i]=ch[p][i]; 53 } 54 } 55 } 56 57 inline void run_fa(int j){ 58 int i,k1;//printf("j:%d ",j); 59 for(i=0;i<=tot;i++)for(k1=0;k1<=tot;k1++) 60 if(fa[i][j-1][k1])fa[i][j]|=fa[k1][j-1]; 61 // for(i=0;i<=tot;i++)for(k1=0;k1<=tot;k1++)if(fa[i][j][k1])printf(" %d->%d ",k1,i); 62 } 63 inline void run_f(int j){ 64 int i,k;register int k1;//printf("j:%d ",j); 65 for(i=0;i<=tot;i++)for(k=0;k<=tot;k++)if(fa[k][j][i]){ 66 for(k1=0;k1<=tot;k1++)if(fa[k1][j-1][i]&&fa[k][j-1][k1]) 67 upd(f[i][j][k],f[i][j-1][k1]+f[k1][j-1][k]);//,printf(" %d-->%d-->%d ",i,k1,k); 68 }else f[i][j][k]=-inf; 69 } 70 inline void run_merge(int j){ 71 int i,k;register int k1; 72 if(first){ 73 first=0; 74 for(i=0;i<=tot;i++)for(k=0;k<=tot;k++)g[i][now][k]=f[i][j-1][k]; 75 return; 76 } 77 for(i=0;i<=tot;i++)for(k=0;k<=tot;k++) 78 for(g[i][now][k]=-inf,k1=0;k1<=tot;k1++)if(fa[k][j-1][k1]) 79 upd(g[i][now][k],g[i][pre][k1]+f[k1][j-1][k]); 80 } 81 82 83 84 int main(){ 85 n=read(),scanf("%I64d",&L); 86 for(i=1;i<=n;i++)v[i]=read(); 87 for(i=1;i<=n;i++)scanf("%s",s+1),trie(strlen(s+1),v[i]); 88 getfail(); 89 90 int a=0; 91 for(i=0;i<=tot;i++)for(k=0;k<=tot;k++)f[i][0][k]=-inf; 92 for(i=0;i<=tot;i++)for(j=0;j<26;j++)fa[next[i][j]][0][i]=1,f[i][0][next[i][j]]=val[next[i][j]]; 93 94 // for(i=0;i<=tot;i++)for(int k1=0;k1<=tot;k1++)if(fa[i][0][k1])printf(" %d->%d ",k1,i); 95 96 now=1,pre=0; 97 while(L){ 98 a++; 99 if(L&1)run_merge(a),swap(now,pre); 100 L>>=1; 101 if(!L)break; 102 run_fa(a),run_f(a); 103 } 104 ll ans=0; 105 for(i=0;i<=tot;i++)upd(ans,g[0][pre][i]); 106 printf("%I64d ",ans); 107 }
比赛的时候这道题肝了整整1h。。。最后1min才过的样例..竟然就过掉了