BJ模拟:Circle Of Stone(KMP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/79981487

传送门

题意:

桌子上有 n个石头围成一个环。每个石头都有一种颜色。每种颜色可以由小写英文字母表示,所以总共有26种颜色。不同的石头可能有相同的颜色。
如果每一对相邻的石头都是不同颜色的,则称这 n 个石头构成的环是美丽的。两个石头是相邻的充要条件是这两个石头中间没有其它石头。
现在,你可以从这 n 个石头中拿走一段连续的石头(可以为空),且你只能拿一次。
你的任务是对于每个k(0kn1) ,判断是否存在一种取石头的方案,使得在拿走 k个连续的石头后,剩下的nk 个石头构成的环是美丽的。

题解:
相邻位置相同把可选的位置变为若干区间,我们对于每个区间单独考虑:

判断k合法等价于判断是否存在长度为nk的子区间使得两端不同,考虑如果不合法,则又等价于任意ai=ai+nk1,即为存在周期nk1

周期和border相对应,利用KMP寻找border,时间复杂度O(n)

#include <bits/stdc++.h>
using namespace std;

const int N=2e6+50;
int n,T,f[N],vis[N],vs,nxt[N],ans[N];
char ch[N],s[N];
inline void solve(int l,int r) {
    int len=r-l+1;
    for(int i=1;i<=len;i++) s[i]=ch[l+i-1];
    for(int i=2,j=0;i<=len;i++) {
        while(j&&s[j+1]!=s[i]) j=nxt[j];
        if(s[j+1]==s[i]) ++j;
        nxt[i]=j;
    }
    ++vs;
    for(int j=nxt[len];j;j=nxt[j]) vis[len-j]=vs;
    for(int j=0;j<len && j<n; ++j) 
        if(vis[j]!=vs) ans[n-j-1]=1;
}
inline void solve() {
    n=strlen(ch+1);
    memcpy(ch+n+1,ch+1,sizeof(char)*n);
    memset(ans,0,sizeof(int)*n);
    for(int i=1,j=1;i<=2*n;i=++j) {
        while(j<2*n && ch[j]!=ch[j+1]) ++j;
        solve(i,j); 
    }
    printf("Case %d: ",++T);
    for(int i=0;i<n;i++) putchar('0'+ans[i]);
    putchar('\n');
}
int main() {
    while(~scanf("%s",ch+1)) solve();
}
阅读更多

没有更多推荐了,返回首页