[loj3396]novel
建立AC自动机,记和分别表示的深度(从开始)和失配指针
记表示以为结束节点的字符串权值和
对于字符串,定义表示在AC自动机上的位置,则
在此基础上,问题即对所有求,并将分为三类讨论:
1. ,单独维护,转移即
2. ,注意到后者随着增加单调不降,即依次执行:
- 全局加上(由于的情况无意义)
- 对于,在当前序列末尾加入
- 查询
关于查询,二分枚举答案,即判定是否存在
维护前者的凸包(自变量为),注意到减小无意义,进而可以用指针代替二分
关于加入的,记,则所求的即以为后缀
注意到是某个串的前缀(即对应位置),可以预处理出(参考)
对反串建立AC自动机,在其中找到所在位置,并依次加入前的字符即可
前者可以对每个串均预处理出(倒序枚举长度跳树),后者即加上对应位置的
3. ,可以利用所对应前缀所求出的结果
为了保证结果间的顺序,处理完前两种情况后在AC自动机上bfs一遍即可
时间复杂度为,可以通过

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 }
分类:
loj
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2021-07-10 [loj3075]组合数求和