题解-CF961F k-substrings

题面

CF961F k-substrings

给定字符串 (s),求每个左右端删除长度相等的子串的最长奇 border 长度。

数据范围:(2le |S|le 10^6)


题解

其实是水题,vp 的时候比较懒散,写了个 z-function 发现不行就睡大觉去了,补题的时候画了幅图不能丢了只好写篇题解(完美的理由)。

注意到一段长为 (n) 的字符串掐头去尾后黄色的这段仍然是新字符串的 border

并且新字符串的 border 可以更大,所以两次答案满足 (a_0-2le a_1)

如果从中间最小的子串往两边算,那么答案 (a) 每次最多增加 (2),可能减少。

所以可以每次先给答案 (+2),再一直减到是 border 为止。

判断 border 可以用 hash,时间复杂度 (Theta(n))


代码

//George1123
#include <bits/stdc++.h>
using namespace std;

typedef long long i64;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef vector<int> vi;
typedef pair<int,int> pii;

#define x first
#define y second
#define sz(a) (int)((a).size())
#define all(a) (a).begin(),(a).end()
#define R(i,n) for(int i=0;i<(n);++i)
#define L(i,n) for(int i=(n)-1;i>=0;--i)

constexpr int inf32=0x3f3f3f3f;
constexpr i64 inf64=0x3f3f3f3f3f3f3f3f;

constexpr int mod=1000000007;

struct mint{
    int x;
    mint(int x=0):x(x){}
    friend mint operator+
    (const mint a,const mint &b){
        int x=a.x+b.x;
        return mint(x>=mod?x-mod:x);
    }
    friend mint operator-
    (const mint a,const mint &b){
        int x=a.x-b.x;
        return mint(x<0?x+mod:x);
    }
    friend mint operator*
    (const mint a,const mint &b){
        return mint(1ll*a.x*b.x%mod);
    }
};

int mypow(int a,int x=mod-2,int res=1){
    for(;x;x>>=1,a=(mint(a)*a).x)
        if(x&1) res=(mint(res)*a).x;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);

    int n;
    string s;
    cin>>n>>s;

    constexpr int B=3917;
    vi p(n+1),pw(n+1);
    pw[0]=1;
    R(i,n) pw[i+1]=(mint(pw[i])*B).x;
    R(i,n) p[i+1]=(mint(p[i])*B+s[i]).x;
    auto sec=[&](int l,int r){
        int res=(mint(p[r])-mint(p[l])*pw[r-l]).x;
        return res;
    };

    vi res(n+1>>1);
    if((~n&1)&&(s[n-1>>1]==s[
    n>>1])) res[n-1>>1]=1;
    else res[n-1>>1]=-1;
    L(i,n-1>>1){
        res[i]=res[i+1]+2;
        for(;res[i]>-1;res[i]-=2)
            if(sec(i,i+res[i])==sec(n-i-res[i],n-i))
                break;
    }
    R(i,n+1>>1) cout<<res[i]<<' ';
    cout<<'
';

    return 0;
}

/* stuff you should look for
	* int overflow, array bounds
	* special cases (n=1?)
	* do smth instead of nothing and stay organized
	* WRITE STUFF DOWN
	* DON'T GET STUCK ON ONE APPROACH
*/

沉舟侧畔千帆过,病树前头万木春,退役了!

原文地址:https://www.cnblogs.com/George1123/p/14334397.html