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_a\cdot 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\n",ans/d);
    return 0;
}

Solution2

我们用倍增的思想来做题。

弄一个倍增数组 \(go\) ,拿 \(pair\) 储存。

\(go_{k,idx(i,j)}\) 为从 \(a\) 的第 \(i\) 位, \(c\) 的第 \(j\) 位开始匹配,匹配 \(c\)\(2^k\) 位之后, \(first\) 表示此时两个串上的位置, \(second\) 为过了几个 \(a\) ,递推数组即可。

二分匹配长度,求得答案。

时间复杂度: \(O(len_a\cdot len_b\log(len_a\cdot 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\n",l/(lenc*d));
    return 0;
}
posted @ 2020-10-14 21:38  jasony_sam  阅读(80)  评论(0编辑  收藏  举报