刚看到这题,最有想法,这不是一道水题吗!
然后脑抽打了个后缀数组加KMP(其实只用KMP就好了),然后打的又臭又长,最后还爆零了。我的KMP尽然从1开始搜!!!!!TAT
主要思路:分两种情况
1、S比T短,设S在T中出现次数为o,然后答案先加上n*o,然后再找中间出现的次数,设S的长度为m,把T的后m-1个和T的前m-1个组成新的字符串A,然后求得S在A中的出现次数p,然后答案再加上p*(n-1)。
2、S比T长,先把T增添到比S长,假设增添了b次,那么有 nb 个串可以做上面的操作,然后还剩下一些字符串这些字符串肯定比S小,那么就把T的后m-1个串与剩下的串合并,再得出答案相加就好了。
看起来写的很长,其实很简单。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=300007;
int i,j,k,l,t,m,len1,len2,p[maxn],da,len3;
char s[maxn],st[maxn],sr[maxn],sq[maxn],ss[maxn];
int sa[maxn],rank[maxn],height[maxn],zhi[maxn],fu[maxn],q[maxn],w,zuo,you,len4,len5;
int js[maxn];
long long ans,n,nn,bei;
int main(){
scanf("%lld",&n);
scanf("%s",s+1);len1=strlen(s+1);
fo(i,2,len1){
while(k>0&&s[i]!=s[k+1])k=p[k];
if(s[i]==s[k+1])k++;
p[i]=k;
}
p[1]=0;
scanf("%s",st+1);len2=strlen(st+1);
if(len1<=len2){
k=0;l=0;
fo(i,1,len2){
while(k>0&&st[i]!=s[k+1])k=p[k];
if(st[i]==s[k+1])k++;
if(k==len1){
l++;
k=p[k];
}
}
ans=l*n;
fo(i,len2-len1+2,len2)sr[++len3]=st[i];
fo(i,1,len1-1)sr[++len3]=st[i];
k=0;w=0;l=0;
fo(i,1,len3){
while(k>0&&sr[i]!=s[k+1])k=p[k];
if(sr[i]==s[k+1])k++;
if(k==len1){
l++;
k=p[k];
}
}
ans=ans+l*(n-1);
printf("%lld\n",ans);
}
else{
while(len41,len2)sq[++len4]=st[i];
}
nn=n/bei;
k=0;l=0;
fo(i,1,len4){
while(k>0&&sq[i]!=s[k+1])k=p[k];
if(sq[i]==s[k+1])k++;
if(k==len1){
k=p[k];
l++;
}
}
ans=l*nn;
fo(i,len4-len1+2,len4)sr[++len3]=sq[i];
fo(i,1,len1-1)sr[++len3]=sq[i];
k=0;w=0;l=0;
fo(i,1,len3){
while(k>0&&sr[i]!=s[k+1])k=p[k];
if(sr[i]==s[k+1])k++;
if(k==len1){
k=p[k];
l++;
}
}
ans=ans+l*(nn-1);
fo(i,len4-len1+2,len4)ss[++len5]=sq[i];
fo(j,1,n-nn*bei)fo(i,1,len2)ss[++len5]=st[i];
k=0;l=0;
fo(i,1,len5){
while(k>0&&ss[i]!=s[k+1])k=p[k];
if(ss[i]==s[k+1])k++;
if(k==len1){
k=p[k];
l++;
}
}
ans+=l;
printf("%lld\n",ans);
}
}