• [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
    ",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 }
    View Code

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

  • 相关阅读:
    archlinux .bash_history
    Ubuntu环境下挂载新硬盘
    软碟通 UltraISO U启替代品 Win32DiskImager 无设备 无盘符 无u盘 无优盘 解决方案 之diskpart
    delphi Integer overflow
    MSBuild Tools offline
    delphi synedit免费的拼写检查器dll
    git 自定义命令行
    lua编译
    gcc ar
    Windows Subsystem for Linux (WSL)挂载移动硬盘U盘 卸载 c d 盘
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5673054.html
Copyright © 2020-2023  润新知