zoukankan      html  css  js  c++  java
  • 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]-2leq 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;
    }
  • 相关阅读:
    最近有人说我欺骗消费者,今天来一波视频分享
    前端 Java Python等资源合集大放送
    dubbo源码学习(四):暴露服务的过程
    dubbo源码学习(二) : spring 自定义标签
    Dubbo多注册中心和Zookeeper服务的迁移
    线程各种状态转换分析
    java并发之同步辅助类CountDownLatch
    工作5年的Java程序员,才学会阅读源码,可悲吗?
    【阿里面试系列】Java线程的应用及挑战
    「阿里面试系列」搞懂并发编程,轻松应对80%的面试场景
  • 原文地址:https://www.cnblogs.com/five20/p/9353217.html
Copyright © 2011-2022 走看看