xz=zy
其实对应的就是把x的某一段前缀减下来贴到后面或者把y的某一段前缀贴下来到前面
如果相等则可以,这点可以在纸上模拟。因为y一直在变,所以我们考虑预处理x
对比字符串是否相等,使用哈希即可,本题使用了双哈希避免被卡。
我们关注到,当我们求得最小能够剪切成功的段时,答案并不是只有这个,因为如果串中有循环节,那么我们加上循环节长度也能获得新的答案。因此我们继续考虑预处理最小循环节。
这样这道题就做完了

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; char s[N],t[N]; const int mod1=1e9+7; const int mod2=1e9+9; const int base=131; map<ll,int> m1; int n,m,q; int nxt[N]; ll p1[N],p2[N]; struct node{ ll l,r; }h[N]; int pos[N]; void Hash(){ p1[0]=1,p2[0]=1; for(int i=1;i<=n;i++){ p1[i]=p1[i-1]*base%mod1; p2[i]=p2[i-1]*base%mod2; h[i].l=(h[i-1].l*base%mod1+(s[i]-'0'))%mod1; h[i].r=(h[i-1].r*base%mod2+(s[i]-'0'))%mod2; } } ll get(int l,int r){ ll h1=(h[r].l-(h[l-1].l*p1[r-l+1]%mod1)+mod1)%mod1; ll h2=(h[r].r-(h[l-1].r*p2[r-l+1]%mod2)+mod2)%mod2; return h1+h2; } int main(){ int T; cin>>T; while(T--){ int i; scanf("%d%d%d",&n,&m,&q); scanf("%s",s+1); scanf("%s",t+1); m1.clear(); nxt[0]=-1; int cnt=0; for(int i=1;i<=m;i++){ int p=nxt[i-1]; while(p>=0&&t[p+1]!=t[i]) p=nxt[p]; nxt[i]=p+1; } int len=m-nxt[m]; if(nxt[m]*2<m) len=m; Hash(); node x={0,0}; for(i=1;i<=m;i++){ ll h1=(x.l*base%mod1+(t[i]-'0')+mod1)%mod1; ll h2=(x.r*base%mod2+(t[i]-'0')+mod2)%mod2; x={h1,h2}; } for(i=1;i<=m;i++){ ll h1=(x.l*base%mod1+(t[i]-'0')-(ll)(t[i]-'0')*p1[m]%mod1+mod1)%mod1; ll h2=(x.r*base%mod2+(t[i]-'0')-(ll)(t[i]-'0')*p2[m]%mod2+mod2)%mod2; x={h1,h2}; if(!m1[h1+h2]){ m1[h1+h2]=++cnt; pos[cnt]=i; } } while(q--){ ll x,y; scanf("%lld%lld",&x,&y); auto tmp=get(x,x+m-1); if(!m1[tmp]){ printf("0 "); } else{ int d=m1[tmp]; printf("%lld ",(ll)(y-pos[d])/len+1); } } } return 0; }