这里介绍两种做法,感觉都很巧妙。
Solution 1
观察题面,发现 (|a|,|c|leq 100) ,所以可以像 (KMP) 那样,造一个 (nxt) 数组,然后再弄一个 (cnt) 数组。
其中 (cnt_i) 表示从 (c_i) 开始匹配,把 (a) 串扫一遍有几组匹配, (nxt_i) 表示 (c_i) 匹配完一个 (a) 到了 (c) 的哪一位。
然后从 (1) 到 (b) ,每次跳 (nxt) , (ans+=cnt) 即可。
时间复杂度: (O(len_acdot len_b)+O(b)=O(b))
代码1
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=110;
ll cnt[N],nxt[N],b,d,lena,lenc,ans;
char a[N],c[N];
int main(){
scanf("%lld%lld%s%s",&b,&d,a,c);
lena=strlen(a),lenc=strlen(c);
for(int i=0,x;i<lenc;i++){
x=i;
for(int j=0;j<lena;j++)
if(a[j]==c[x]){
x++;
if(x==lenc) cnt[i]++,x=0;
}
nxt[i]=x;
}
int pos=0;
for(int i=1;i<=b;i++){
ans+=cnt[pos];
pos=nxt[pos];
}
printf("%lld
",ans/d);
return 0;
}
Solution2
我们用倍增的思想来做题。
弄一个倍增数组 (go) ,拿 (pair) 储存。
设 (go_{k,idx(i,j)}) 为从 (a) 的第 (i) 位, (c) 的第 (j) 位开始匹配,匹配 (c) 的 (2^k) 位之后, (first) 表示此时两个串上的位置, (second) 为过了几个 (a) ,递推数组即可。
二分匹配长度,求得答案。
时间复杂度: (O(len_acdot len_blog(len_acdot b)))
代码2
#include<bits/stdc++.h>
#define ll long long
#define PII pair<int,ll>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
char a[N],c[N];
ll lena,lenc,b,d;
PII go[30][N*N];
inline int idx(int i,int j){
return i*lenc+j;
}
ll solve(int dis){
int tmp=idx(0,0);
ll res=0;
for(int i=0;i<30;i++){
if(dis>>i&1){
res+=go[i][tmp].second;
tmp=go[i][tmp].first;
}
}
return res;
}
int main(){
scanf("%lld%lld%s%s",&b,&d,a,c);
lena=strlen(a);lenc=strlen(c);
for(int i=0;i<lena;i++)
for(int j=0;j<lenc;j++){
int id=idx(i,j);
go[0][id]=make_pair(id,INF);
for(int k=0;k<lena;k++)
if(a[(i+k)%lena]==c[j]){
go[0][id]=make_pair(idx((i+k+1)%lena,(j+1)%lenc),(i==0)||((i+k)/lena));
break;
}
}
for(int i=1;i<30;i++)
for(int j=0;j<lena*lenc;j++){
int nxt=go[i-1][j].first;
go[i][j]=make_pair(go[i-1][nxt].first,go[i-1][j].second+go[i-1][nxt].second);
}
ll l=0,r=INF;
while(l<r){
ll mid=(l+r+1)>>1;
if(solve(mid)<=b) l=mid;
else r=mid-1;
}
printf("%lld
",l/(lenc*d));
return 0;
}