[loj3396]novel

建立AC自动机,记|xfailx分别表示x的深度(从0开始)和失配指针

Wx表示以x为结束节点的字符串权值和,Sx=z(fail)xWz

对于字符串si,定义posr表示si[1,r]在AC自动机上的位置,则
g(si[l,r])=g(si[l,r))+x(fail)posr,|x|rl+1Wx
在此基础上,问题即对所有rmax1lrg(si[l,r])rl+1,并将l分为三类讨论:

1. l=1,单独维护,转移即g(si[1,r])=g(si[1,r))+Sposr

2. 2lr|failposr|,注意到后者随着r增加单调不降,即依次执行:

  • 全局加上Sfailposr(由于i2,x=posr的情况无意义)
  • 对于r|failposr1|lr|failposr|,在当前序列末尾加入g(si[l,r])
  • 查询maxl[2,r|failposr|]g(si[l,r])rl+1

关于查询,二分枚举答案k,即判定是否存在(l1)k+g(si[l,r])rk

维护前者的凸包(自变量为k),注意到k减小无意义,进而可以用指针代替二分

关于加入的g(si[l,r]),记t=si(r|failposr|,r],则所求的si[l,r]即以t为后缀

注意到t是某个串的前缀(即failposr对应位置),可以预处理出g(t)(参考1.

对反串建立AC自动机,在其中找到t所在位置,并依次加入t前的字符即可

前者可以对每个串均预处理出(倒序枚举长度跳fail树),后者即加上对应位置的Sx

3. r|failposr|<lr,可以利用t所对应前缀所求出的结果

为了保证结果间的顺序,处理完前两种情况后在AC自动机上bfs一遍即可

时间复杂度为o(m),可以通过

复制代码
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define M 5000005
  5 #define mod 998244353
  6 #define ll long long
  7 #define LL __int128
  8 int T,n,x,l,ql,qr,lst,Ans,inv[M],pos[M],q[M];
  9 char s[M];ll tag,val[M];vector<int>ch[N];
 10 struct Frac{
 11     ll x;int y;
 12     int get(){
 13         return x%mod*inv[y]%mod;
 14     }
 15     bool operator < (const Frac &n)const{
 16         return (LL)x*n.y<(LL)y*n.x;
 17     }
 18 }ans[M];
 19 struct AC{
 20     int V=1,dep[M],nex[M],ch[M][4];
 21     ll W[M],S[M],g[M];
 22     queue<int>q;vector<int>dfn,v[N];
 23     void add(char *s,int l,int id,int x){
 24         int k=1;v[id].push_back(1);
 25         for(int i=0;i<l;i++){
 26             int c=s[i]-'a';
 27             if (!ch[k][c])ch[k][c]=++V,dep[V]=dep[k]+1;
 28             k=ch[k][c],v[id].push_back(k);
 29         }
 30         W[k]+=x;
 31     }
 32     void build(){
 33         for(int i=0;i<4;i++){
 34             if (!ch[1][i])ch[1][i]=1;
 35             else nex[ch[1][i]]=1,q.push(ch[1][i]);
 36         }
 37         while (!q.empty()){
 38             int k=q.front();q.pop();
 39             S[k]=W[k]+S[nex[k]],g[k]+=S[k],dfn.push_back(k);
 40             for(int i=0;i<4;i++)
 41                 if (!ch[k][i])ch[k][i]=ch[nex[k]][i];
 42                 else{
 43                     nex[ch[k][i]]=ch[nex[k]][i];
 44                     g[ch[k][i]]+=g[k],q.push(ch[k][i]);
 45                 }
 46         }
 47     }
 48 }T1,T2;
 49 Frac get(int x,int y){
 50     return Frac{val[x]-val[y],y-x};
 51 }
 52 void add(int k){
 53     if (k==1)return;
 54     while ((ql<qr)&&(get(q[qr],k)<get(q[qr-1],q[qr])))qr--;
 55     q[++qr]=k;
 56 }
 57 Frac query(int k){
 58     if (ql>qr)return Frac{0,1};
 59     val[k+1]=-tag;
 60     while ((ql<qr)&&(get(q[ql],k+1)<get(q[ql+1],k+1)))ql++;
 61     return get(q[ql],k+1);
 62 }
 63 int main(){
 64     inv[0]=inv[1]=1;
 65     for(int i=2;i<M;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
 66     scanf("%d%d",&n,&T);
 67     for(int i=1;i<=n;i++){
 68         scanf("%s%d",s,&x),l=strlen(s);
 69         for(int j=0;j<l;j++)ch[i].push_back(s[j]-'a');
 70         T1.add(s,l,i,x),reverse(s,s+l),T2.add(s,l,i,x);
 71     }
 72     T1.build(),T2.build();
 73     for(int i=1;i<=n;i++){
 74         l=ch[i].size();
 75         for(int j=l,k=T2.v[i][l];j>=0;j--){
 76             while (j<T2.dep[k])k=T2.nex[k];
 77             pos[T1.v[i][j]]=k;
 78         }
 79     }
 80     for(int i=1;i<=n;i++){
 81         l=ch[i].size(),ql=1,qr=lst=0;
 82         for(int r=1;r<=l;r++){
 83             int k=T1.v[i][r];tag+=T1.S[T1.nex[k]];
 84             int k0=pos[T1.nex[k]];ll s=T1.g[T1.nex[k]];
 85             for(int j=r-T1.dep[T1.nex[k]];j>=r-T1.dep[T1.nex[lst]];j--){
 86                 k0=T2.ch[k0][ch[i][j-1]],s+=T2.S[k0],val[j]=s-tag;
 87             }
 88             for(int j=r-T1.dep[T1.nex[lst]];j<=r-T1.dep[T1.nex[k]];j++)add(j);
 89             lst=k,ans[k]=max(query(r),Frac{T1.g[k],r});
 90         }
 91     }
 92     for(int i:T1.dfn)ans[i]=max(ans[i],ans[T1.nex[i]]);
 93     for(int i=1;i<=n;i++){
 94         l=ch[i].size();Frac s=Frac{0,1};
 95         for(int j=1;j<=l;j++)s=max(s,ans[T1.v[i][j]]),Ans^=s.get();
 96         if ((!T)&&(i==1))printf("%.6f\n",1.0*s.x/s.y);
 97     }
 98     if (T)printf("%d\n",Ans);
 99     return 0;
100 }
View Code
复制代码

 

posted @   PYWBKTDA  阅读(285)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-07-10 [loj3075]组合数求和
点击右上角即可分享
微信分享提示