Neighboring Characters zoj 4010(hash)

题目连接:这里写链接内容
思路:题目要求从任意位置删除k个元素使得没有相邻的字母相同,如果我们去考虑删除一些元素,再得到删除后的元素,这样子显然是很麻烦的,而且复杂度也不允许,那么我们直接考虑
保留后的元素,这里保留后的元素有可能本身就是连续的,也有可能是有两段拼接而成的,第二种显然是不好处理的,那么我们考虑将环变成链,那么这样所有的可能保留下来的都是本身就是连续的,那么接下来显然是要找出所有连续的没有相邻的为相同的字串,找到这些子串后,我们去枚举保留下来的长度,接下来有个问题就是,就算保留下来的是满足的,但是有可能首尾是相同的,我们手动模拟后发现,其实就是判断下前缀后缀是否相同就行了,因为如果前缀后缀完全相同,那么对于当前的字串是不可能找到当前枚举长度首尾不相同的子串的,用hash判断即可
O(n)
accode

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define ULL unsigned long long
using namespace std;
const int maxn = 1e6+2;
ULL jz[maxn*2];
int base = 233;
ULL S[maxn*2];
char s[maxn*2];
int ans[maxn];
ULL getHash(int s,int e)
{
    return S[e]-S[s-1]*jz[e-s+1];
}
int main()
{
    int t;
    jz[0] = 1;
    for(int i = 1;i<2*maxn;i++){
        jz[i] = jz[i-1]*base;
    }
    scanf("%d",&t);
    while(t--){
        scanf("%s",s+1);
        int len = strlen(s+1);
        for(int i = 1;i<=len;i++){
            s[len+i] = s[i];
        }
        S[0] = 0;
        for(int i = 1;i<=2*len;i++){
            S[i] = S[i-1]*base + (s[i]-'a')+1;
        }
        memset(ans,0,sizeof(ans));
        int i = 1;
        int j = i+1;
        for( i = 1;i<=2*len;i = j)
        {
            j = i+1;
            while(j<=2*len&&s[j]!=s[j-1]){
                j++;
            }
            int L = j-1-i+1;
            //cout<<i<<' '<<j-1<<' '<<L<<endl;
            for(int k = 2;k<=L;k++){
                if(k>len) break;
               // cout<<i<<' '<<j-k<<' '<<k<<' '<<i+k-1<<' '<<j-1<<endl;
                if(getHash(i,j-k)!=getHash(i+k-1,j-1)) ans[len-k] = 1;
            }
        }
        ans[len-1] = 1;
        for(int i = 0;i<len;i++){
            printf("%d",ans[i]);
        }
        puts("");
    }
}

猜你喜欢

转载自blog.csdn.net/w571523631/article/details/79640961
ZOJ