[CF526D] Om Nom and Necklace - 扩展kmp,差分

Description

给定一个长度为 \(n\) 的字符串 \(S\),求它的所有前缀中,哪些可以被划分为 \(ABAB...ABA\) 的形式,其中 \(A,B\) 是可以为空的串,且一共包含了 \(k\) 组 \(AB\)。

Solution

考虑令 \(S=AB\),枚举 \(S\) 的长度 \(i\),我们只需要检查 \(LCP(ji+1,1) \ge i, j=1..k-1\),如果都满足,则可以将答案序列中往后的一段覆盖为 \(1\)

用扩展 KMP 可以在 \(O(n)\) 时间内完成对 \(LCP(i,1), i=1..n\) 的计算

所有被枚举的长度共有 \(O(n/k)\) 个,每次需要检查 \(O(k)\) 个位置,故总复杂度 \(O(n)\)

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

#define int long long
const int N = 1000005;

namespace exkmp
{
int nxt[N]; // x[0..m-1] x[i..m-1] LCP
int ext[N]; // x[0..m-1] y[i..n-1] LCP
void presolve(const char* x,int m)
{
    nxt[0]=m;
    int j=0;
    while(j+1<m&&x[j]==x[j+1]) j++;
    nxt[1]=j;
    int k=1;
    for(int i=2; i<m; i++)
    {
        int p=nxt[k]+k-1, l=nxt[i-k];
        if(i+l<p+1) nxt[i]=l;
        else
        {
            j=max(0ll,p-i+1);
            while(i+j<m && x[i+j]==x[j]) j++;
            nxt[i]=j;
            k=i;
        }
    }
}
void presolve(string s)
{
    presolve(s.c_str(),s.length());
}
int lcp(int p)
{
    return nxt[p-1];
}
} // namespace exkmp

int n,k;
string s;

namespace sumsolver
{
int a[N];
void modify(int l,int r)
{
    r=min(r,n);
    l=max(l,1ll);
    a[l]++;
    a[r+1]--;
}
void solve()
{
    for(int i=1;i<=n;i++) a[i]+=a[i-1];
}
int query(int p)
{
    return a[p]?1:0;
}
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>k>>s;
    exkmp::presolve(s);

    for(int i=1;i*k<=n;i++)
    {
        int flag=1;
        for(int j=1;j<k;j++)
        {
            if(exkmp::lcp(i*j+1)<i)
            {
                flag=0;
                break;
            }
        }
        if(flag)
        {
            sumsolver::modify(i*k,i*k+min(exkmp::lcp(i*k+1),i));
        }
    }

    sumsolver::solve();
    for(int i=1;i<=n;i++) cout<<sumsolver::query(i);
}

上一篇:初学Python学习日志(二)


下一篇:论文笔记:GEOMETRIC CONTEXT AND ORIENTATION MAP COMBINATION FOR INDOOR CORRIDOR MODELING USING A SINGLE I