[CF526D] Om Nom and Necklace - 擴充套件kmp,差分
阿新 • • 發佈:2020-08-28
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)\)
#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); }