字符串哈希-k-substrings-CodeForces-961F

字符串哈希-k-substrings-CodeForces-961F

题意:

给 定 一 个 长 度 为 n 的 字 符 串 s 。 定 义 k 串 为 s 中 , 第 k 个 字 符 到 倒 数 第 k 个 字 符 构 成 的 子 串 。 抽 象 地 , 即 s u b s k = s [ k , n + 1 − k ] 。 给定一个长度为n的字符串s。\\定义k串为s中,第k个字符到倒数第k个字符构成的子串。\\抽象地,即subs_k=s[k,n+1-k]。 nskskksubsk=s[k,n+1k]

对 长 度 为 n 的 字 符 串 而 言 , 共 有 ⌈ n 2 ⌉ 个 k 串 , 分 别 是 s u b s 1 , s u b s 2 , . . . , s u b s n 2 。 显 然 , s u b s 1 = s [ 1 , n ] = s 。 对长度为n的字符串而言,共有\lceil\frac{n}{2}\rceil个k串,分别是subs_1,subs_2,...,subs_{\frac{n}{2}}。\\显然,subs_1=s[1,n]=s。 n2nksubs1,subs2,...,subs2nsubs1=s[1,n]=s

求 每 一 个 k 串 中 , 最 长 相 同 前 后 缀 的 长 度 。 求每一个k串中,最长相同前后缀的长度。 k

Sample Input:
15
bcabcabcabcabca

Sample Output:
9 7 5 3 1 -1 -1 -1


Sample Input:
24
abaaabaaaabaaabaaaabaaab

Sample Output:
15 13 11 9 7 5 3 1 1 -1 -1 1


Sample Input:
19
cabcabbcabcabbcabca

Sample Output:
5 3 1 -1 -1 1 1 -1 -1 -1

Note:
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

数据范围:

s 的 长 度 n ∈ [ 2 , 1000000 ] 。 s的长度n∈[2,1000000]。 sn[2,1000000]

题解:

从 短 到 长 , 枚 举 每 一 个 k 串 , 再 从 大 到 小 , 枚 举 最 大 相 同 前 后 缀 的 长 度 , 用 哈 希 来 判 断 是 否 相 等 。 从短到长,枚举每一个k串,再从大到小,枚举最大相同前后缀的长度,用哈希来判断是否相等。 k

有 一 个 性 质 需 要 注 意 : 设 a n s [ i ] 表 示 第 i 长 的 k 串 的 最 大 相 同 前 后 缀 的 长 度 , 则 a n s [ i ] < = a n s [ i + 1 ] + 2 。 这 很 好 理 解 , 枚 举 k 串 时 每 次 只 在 前 一 个 k 串 的 首 尾 增 加 2 个 字 符 , 最 好 情 况 就 是 增 加 的 2 个 字 符 恰 好 在 原 来 的 基 础 上 把 相 同 前 后 缀 拓 宽 了 2 个 字 符 , 如 样 例 一 的 解 释 。 那 么 第 i 个 k 串 的 答 案 范 围 就 在 [ − 1 , a n s [ i + 1 ] + 2 ] 之 间 来 取 。 有一个性质需要注意:\\设ans[i]表示第i长的k串的最大相同前后缀的长度,则ans[i]<=ans[i+1]+2。\\这很好理解,枚举k串时每次只在前一个k串的首尾增加2个字符,\\最好情况就是增加的2个字符恰好在原来的基础上把相同前后缀拓宽了2个字符,如样例一的解释。\\那么第i个k串的答案范围就在[-1,ans[i+1]+2]之间来取。 ans[i]ikans[i]<=ans[i+1]+2kk222ik[1,ans[i+1]+2]

具体落实:

① 、 首 先 根 据 n 的 奇 偶 性 , 解 决 最 短 的 k 串 的 即 最 后 一 个 k 串 的 相 同 前 后 缀 的 长 度 。 若 n 为 奇 数 , 最 短 的 k 串 长 度 为 1 , 那 么 a n s [ ⌈ n 2 ⌉ ] = − 1 , 若 n 为 偶 数 , 最 短 的 k 串 长 度 为 2 , 判 断 s [ n 2 ] 与 s [ n 2 + 1 ] 是 否 相 等 , 若 相 等 , 则 a n s [ n 2 ] = 1 , 否 则 a n s [ n 2 ] = − 1 。   ② 、 以 2 为 步 长 , 拓 宽 k 串 的 长 度 , 对 第 i 个 k 串 , 在 第 i + 1 个 k 串 的 a n s [ i + 1 ] + 2 到 − 1 之 间 枚 举 答 案 a n s [ i ] 。 ①、首先根据n的奇偶性,解决最短的k串的即最后一个k串的相同前后缀的长度。\\\qquad若n为奇数,最短的k串长度为1,那么ans[\lceil\frac{n}{2}\rceil]=-1,\\\qquad若n为偶数,最短的k串长度为2,判断s[\frac{n}{2}]与s[\frac{n}{2}+1]是否相等,若相等,则ans[\frac{n}{2}]=1,否则ans[\frac{n}{2}]=-1。\\\ \\②、以2为步长,拓宽k串的长度,对第i个k串,在第i+1个k串的ans[i+1]+2到-1之间枚举答案ans[i]。 nkknk1ans[2n]=1nk2s[2n]s[2n+1]ans[2n]=1,ans[2n]=1 2kiki+1kans[i+1]+21ans[i]


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const int N=2e6+10;
const int base=131;
const int mod=1e9+7;
char s[N];
int n,ans[N/2];
ll h[N],p[N];

ll get(int l,int r)
{
    return (h[r]-h[l-1]*p[r-l+1]%mod+mod)%mod;
}

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

    p[0]=1;
    for(int i=1;i<=n;i++) p[i]=p[i-1]*base%mod;

    for(int i=1;i<=n;i++) h[i]=(h[i-1]*base%mod+s[i]-'a')%mod;

    ///最中间的串,考虑奇偶性
    int l,r;
    int mid=n+1>>1;
    if(n%2==0)
    {
        l=n>>1,r=l+1;
        if(s[l]==s[r]) ans[mid]=1;
        else ans[mid]=-1;
    }
    else ans[mid]=-1,l=r=mid;

    for(int i=mid-1;i>=1;i--)
    {
        l--,r++;  ///k串的左右端点
        for(int j=ans[i+1]+2;j>=-1;j-=2)  ///枚举最大匹配的长度
        {
            if(get(l,l+j-1)==get(r-j+1,r)||j==-1)
            {
                ans[i]=j;
                break;
            }
        }
    }

    for(int i=1;i<=mid;i++) printf("%d ",ans[i]);
    puts("");

    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值