CF961F k-substrings

题目描述

You are given a string s s s consisting of n n n lowercase Latin letters.

Let's denote k k k -substring of s s s as a string subsk=sksk+1..sn+1−k subs_{k}=s_{k}s_{k+1}..s_{n+1-k} subsk=sksk+1..sn+1k . Obviously, subs1=s subs_{1}=s subs1=s , and there are exactly such substrings.

Let's call some string t t t an odd proper suprefix of a string T T T iff the following conditions are met:

  • ∣T∣>∣t∣ |T|>|t| T>t ;
  • ∣t∣ |t| t is an odd number;
  • t t t is simultaneously a prefix and a suffix of T T T .

For evey k k k -substring () of s s s you have to calculate the maximum length of its odd proper suprefix.

输入输出格式

输入格式:

The first line contains one integer n n n (2<=n<=106) (2<=n<=10^{6}) (2<=n<=106) — the length s s s .

The second line contains the string s s s consisting of n n n lowercase Latin letters.

输出格式:

Print integers. i i i -th of them should be equal to maximum length of an odd proper suprefix of i i i -substring of s s s (or −1 -1 1 , if there is no such string that is an odd proper suprefix of i i i -substring).

输入输出样例

输入样例#1: 
15
bcabcabcabcabca
输出样例#1: 
9 7 5 3 1 -1 -1 -1
输入样例#2: 
24
abaaabaaaabaaabaaaabaaab
输出样例#2: 
15 13 11 9 7 5 3 1 1 -1 -1 1
输入样例#3: 
19
cabcabbcabcabbcabca
输出样例#3: 
5 3 1 -1 -1 1 1 -1 -1 -1

说明

The answer for first sample test is folowing:

  • 1-substring: bcabcabcabcabca
  • 2-substring: cabcabcabcabc
  • 3-substring: abcabcabcab
  • 4-substring: bcabcabca
  • 5-substring: cabcabc
  • 6-substring: abcab
  • 7-substring: bca
  • 8-substring: c

 

 

Solution:

  集训第二天,昨天HRZ学长讲的NOI2016我只搞出了一道(话说我是真的菜)。

  今天的字符串专题讲了下本题,然后思路非常巧妙:字符串hash+类似kmp的方法。

  首先字符串hash就随便讲下,直接将每位当作$k$进制数取模就好了,一般$k=131$然后模数搞个质数,当然为了防止出错,可以搞多模数。

  然后我们发现本题的一个性质,那就是$ans[1]-2\leq ans[2]$,这个很显然啊,那么我们移项后得到$ans[1]\leq ans[2]+2$。

  不难想到我们可以从最中间的情况开始考虑,然后往前枚举,对于当前答案$ans[cnt]$,可以肯定的是$ans[cnt]\leq ans[cnt+1]+2$,所以每次答案最多增加一个$2$,若不行就回退,最多减少$n$个$2$(注意不能小于$-1$)。学长说这有点像KMP的算法复杂度证明,显然有一共最多增加$\frac{n}{2}$个$2$,最多减少$\frac{n}{2}$个$2$,所以复杂度是$O(n)$的,具体实现时,只需要取出该长度的两个字符串hash值,比较一下直到相等就好了。有点玄学,但是还是能理解吧。

代码:

 

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const ll N=2000005,M=131,mod1=998244353,mod2=19260817;
ll f[N],p[N],sum[N],ans[N>>1],cnt;
int n;
char s[N];

il void solve(){
    sum[0]=1;
    For(i,1,n) f[i]=(f[i-1]*M+s[i])%mod1,sum[i]=(sum[i-1]*M)%mod1;
    int l,r;
    cnt=n+1>>1;
    if(n&1)ans[cnt]=-1,l=r=n+1>>1;
    else {
        l=n>>1,r=l+1;
        s[l]==s[r]?ans[cnt]=1:ans[cnt]=-1;
    }
    ll p,q;
    while(cnt--){
        ans[cnt]=ans[cnt+1]+2;
        if(!cnt)break;
        l--,r++;
        p=-1,q=1;
        while(ans[cnt]!=-1){
            p=(f[l+ans[cnt]-1]-f[l-1]*sum[ans[cnt]]%mod1+mod1)%mod1;
            q=(f[r]-f[r-ans[cnt]]*sum[ans[cnt]]%mod1+mod1)%mod1;
            if(p==q) break;
            ans[cnt]-=2;
        }
    }
    For(i,1,(n+1)>>1) printf("%lld ",ans[i]);
}


int main(){
    scanf("%d%s",&n,s+1);
    solve();
    return 0;
}

 

转载于:https://www.cnblogs.com/five20/p/9353217.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值