CF314B Sereja and Periods

这里介绍两种做法,感觉都很巧妙。

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;
}
原文地址:https://www.cnblogs.com/jasony/p/13817567.html