[Codeforces 696D] Legen...

  题目大意:

    给出一些匹配串,要造一个长度不超过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\n",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\n",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\n",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\n",k1,i);
 62 }
 63 inline void run_f(int j){
 64     int i,k;register int k1;//printf("j:%d\n",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\n",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\n",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\n",ans);
107 }

比赛的时候这道题肝了整整1h。。。最后1min才过的样例..竟然就过掉了

时间: 2024-10-10 23:40:25

[Codeforces 696D] Legen...的相关文章

Codeforces 696D Legen...(AC自动机 + 矩阵快速幂)

题目大概说给几个字符串,每个字符串都有一个开心值,一个串如果包含一次这些字符串就加上对应的开心值,问长度n的串开心值最多可以是多少. POJ2778..复习下..太弱了都快不会做了.. 这个矩阵的乘法定义是不同的,m[i][j]=max(m1[i][k]+m2[k][j]),即从i走到k能获得的最大值与从k走到j能获得的最大值之和去更新从i到j能获得的最大值. 另外..关于矩阵内的初始值..用-1表示从i不能到j,比如初始的时候,i不能走一步到j结点这时值就应该设置成-1:而不能用0,因为0是有

Codeforces 696 D. Legen...

Description 每个字符串有些价值,问生成长度为 \(l\) 的字符串最多能获得多少价值,总字符数不超过 \(200\), \(l\leqslant 10^{14}\) . Sol AC自动机 + 倍增Floyd. 用AC自动机统计到达每个节点会获得的权值. 然后在AC自动机从根节点开始找一条最长路,就用Floyd倍增就可以了... 发现自己AC自动机做Fail树的时候写错了,改了好久没改出来,最后发现不能直接将根扔进队列里...应该把根的所有子节点扔进去.. 然后类似快速幂做就可以了.

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Codeforces Round #408 (Div. 2) B

Description Zane the wizard is going to perform a magic show shuffling the cups. There are n cups, numbered from 1 to n, placed along the x-axis on a table that has m holes on it. More precisely, cup i is on the table at the position x?=?i. The probl