Codeforces 1909G - Pumping Lemma
这个题思考角度很多,做法也很多。这里介绍一种 @asmend 和我讲的做法。
设 ,那么我们枚举 ,设 的 LCP 长为 ,LCS 长为 ,那么可以得到这组 合法的充要条件是:
- 。
- 。
- 。
考虑第四条限制,我们将所有长度为 的子串的哈希值排序,这样对于每种子串,我们可以知道其出现的位置 。考虑 occurrence 序列的一个性质:对于极长的满足 的连续段 ,必然有 ,这个可以用 WPL 证明。这样考虑对每个这样的连续段统计贡献,设等差数列的公差为 ,长度为 ,因为是等差数列,因此这个连续段内部可能出现的 只有 这 种,枚举之,那么第一、二条限制的作用是将 限制在一个区间内,这样相当于求等差数列中在这个区间内的数的个数,这容易 。因为 ,所以后面复杂度为线性。复杂度瓶颈在排序,如果使用三个与 同阶的质数作为哈希模数并桶排则可以线性。但我直接 sort
以 1996ms 卡了过去就没管了(
const int MAXN=1e7; const int MOD1=1e9+21; const int MOD2=1e9+33; const int BS1=191; const int BS2=193; int qpow(int x,int e,int mod){int ret=1;for(;e;e>>=1,x=1ll*x*x%mod)if(e&1)ret=1ll*ret*x%mod;return ret;} char s[MAXN+5],t[MAXN+5];int n,m,d,pw1,pw2; struct _hash{ int hs1,hs2,pos; _hash(){hs1=hs2=pos=0;} void append(int x){ hs1=(1ll*hs1*BS1+x)%MOD1; hs2=(1ll*hs2*BS2+x)%MOD2; } void del(int x){ hs1=(hs1+1ll*(MOD1-pw1)*x)%MOD1; hs2=(hs2+1ll*(MOD2-pw2)*x)%MOD2; } friend bool operator <(const _hash &X,const _hash &Y){ if(X.hs1!=Y.hs1)return X.hs1<Y.hs1; if(X.hs2!=Y.hs2)return X.hs2<Y.hs2; return X.pos<Y.pos; } friend bool operator ==(const _hash &X,const _hash &Y){ return (X.hs1==Y.hs1&&X.hs2==Y.hs2); } }a[MAXN+5],cur; int limL,limR;ll res=0; int calc(int l,int r,int stp,int rem){ if(l>r)return 0; return (r-rem+stp)/stp-(l-1-rem+stp)/stp; } void work(int l,int r){ for(int i=l;i<r;i++)res+=(a[i+1].pos-a[i].pos==d); for(int L=l,R;L<=r;L=R+1){ if(a[L].pos>limR)break; R=L;while(R<r&&a[R+1].pos-a[R].pos<d)++R; if(L!=R){ int d0=a[L+1].pos-a[L].pos; for(int j=1;j<=R-L;j++)if(d%(j*d0)==0){ int _R=limR,_L=limL-j*d0; res+=calc(max(_L,a[L].pos),min(_R,a[R-j].pos),d0,a[R].pos%d0); } } } } int main(){ scanf("%d%d%s%s",&n,&m,s+1,t+1);d=m-n; pw1=qpow(BS1,d,MOD1);pw2=qpow(BS2,d,MOD2); for(int i=1;i<=m;i++){ cur.append(t[i]); if(i>d)cur.del(t[i-d]); if(i>=d)a[i-d+1]=cur,a[i-d+1].pos=i-d+1; } sort(a+1,a+m-d+2); // for(int i=1;i<=m-d+1;i++)printf("(%d,%d,%d) %d\n",a[i].hs1,a[i].hs2,a[i].hs3,a[i].pos); int len1=0,len2=0; while(len1<n&&s[len1+1]==t[len1+1])++len1; while(len2<n&&s[n-len2]==t[m-len2])++len2; limR=len1+1;limL=m-len2-d+1; for(int l=1,r;l<=m-d+1;l=r){ r=l;while(r<=m-d+1&&a[r]==a[l])++r; work(l,r-1); } printf("%lld\n",res); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2020-12-26 洛谷 P7156 - [USACO20DEC] Cowmistry P(分类讨论+trie 树上 dp)
2020-12-26 洛谷 P7155 [USACO20DEC] Spaceship P(dp)
2020-12-26 洛谷 P7154 - [USACO20DEC] Sleeping Cows P(dp)
2020-12-26 Codeforces 997E - Good Subsegments(线段树维护最小值个数+历史最小值个数之和)