ZOJ_4010 Neighboring Characters(哈希)

Neighboring Characters

Time Limit: 4000 ms
Memory Limit: 65536 KB
Problem Description

Given a string s of length n, let’s define the neighbors of the i-th character ( 1 ≤ i ≤ n 1\le i\le n 1in) as follows:

If 1 < i < n 1<i<n 1<i<n, the neighbors of the i-th character are the (i-1)-th character and the (i+1)-th character;
If i = 1 i=1 i=1, the neighbors of the 1st character are the 2nd character and the n-th character;
If i = n i=n i=n, the neighbors of the n-th character are the (n-1)-th character and the 1st character.
A string s is good, if and only if all the characters in the string are different from their neighbors.

DreamGrid would like to delete k continuous characters from string s to form a new string sk. Note that the n-th character and the 1st character are also continuous (you can consider the string as a ring). Please tell him if it’s possible to make sk a good string for all 0 ≤ k < n 0 \le k <n 0k<n.

Input

There are multiple test cases. The first line of the input contains an integer T, indicating the number of test cases. For each test case:

The first and only line contains a string s( 1 ≤ ∣ S ∣ ≤ 1 0 6 1\le|S|\le10^6 1S106) consists of lowercase English letters.

It’s guaranteed that the sum of |S| over all test cases will not exceed 1.2 ∗ 1 0 7 1.2 * 10 ^ 7 1.2107.

Output

For each test case output one line containing one string of length ∣ S ∣ |S| S consists of ‘0’ and ‘1’. If the i-th (the index starts from 1) character is ‘1’, it is possible to make s i − 1 s_i-1 si1 a good string; If its ‘0’, it is impossible to make s i − 1 s_i-1 si1 a good string.

Sample Input

5
abab
aabbaa
abcabc
abcdef
a

Sample Output

1011
000011
110111
111111
1

题意

有一个字符串,它的首尾是相连的,可以删除它连续的k个字符,如果能使所有相邻的字符不相同,则为1,否则为0,对于所有的k(0<=k<len),求出对应的结果。

题解:

暂且不考虑首尾是否相同,考虑让每个段尽可能的长。将串划分为多段 [ l 1 , r 1 ] , [ l 2 , r 2 ] [l_1,r_1],[l_2,r_2] [l1,r1],[l2,r2]… , l 2 = r 1 + 1 , l 3 = r 2 + 1 l_2 = r_1+1, l_3 = r_2+1 l2=r1+1,l3=r2+1 …,注意它是环,所以最后一段可能是 [ l i , n ] , [ 1 , r n ] [l_i, n], [1, r_n] [li,n],[1,rn]的形式。
分别考虑每一段,判断段内是否存在删除k个连续字符使首尾不相同(前面的划分已保证其他位置相邻字符不同)。
删除k个连续的字符 = 保留 j = l e n − k j = len-k j=lenk个连续的字符,我们将问题转化为考虑是否存在连续j个字符相邻元素不同。
需要j成立,则 s t r [ l ] ! = s t r [ l + j − 1 ] , s t r [ l + 1 ] ! = s t r [ l + j ] . . . . s t r [ r − j + 1 ] ! = s t r [ r ] str[l] != str[l+j-1] ,str[l+1] != str[l+j] .... str[r-j+1] != str[r] str[l]!=str[l+j1],str[l+1]!=str[l+j]....str[rj+1]!=str[r]中有一个成立即可,可以看出等式两边分别是一段的前后缀,只需要判断前后缀是否相同即可。
可以利用hash在O(1)时间内判断两段前后缀是否相等。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 2000100;
const int mod = 1000000007;
char str[maxn];
LL hs[maxn], ss[maxn];
int ans[maxn];
LL geths(int l, int r);

int main()
{
    int t, n, i, j, k;
    ss[0] =  1;
    for(i=1;i<=maxn-50;i++)
        ss[i] = ss[i-1]*26%mod;
    scanf("%d", &t);
    while(t--)
    {
        scanf(" %s", str+1);
        n = strlen(str+1);
        for(i=1;i<=n;i++)
        {
            ans[i] = 0;
            str[i+n] = str[i];
        }
        hs[0] = 0;
        for(i=1;i<=2*n;i++)
            hs[i] = (hs[i-1]*26+str[i]-'a'+1)%mod;
        int l = 1, r = 1;
        while(l<=n)
        {
            while(str[r]!=str[r+1] && r-l+1<n)
                r++;
            for(i=0;i<r-l;i++)
                if(geths(l, l+i) != geths(r-i, r))
                    ans[r-l+1-i] = 1;
            l = r = r+1;
        }
        ans[1] = 1;
        for(i=n;i>=1;i--)
            printf("%d", ans[i]);
        printf("\n");
    }
    return 0;
}

LL geths(int l, int r)
{
    LL ks = hs[l-1]*ss[r-l+1]%mod;
    return (hs[r]-ks+mod)%mod;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值