zoukankan      html  css  js  c++  java
  • [CF526D] Om Nom and Necklace

    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);
    }
    
    
  • 相关阅读:
    【LGOJ4147】玉蟾宫
    【BJWC2012】冻结
    【JSOI2016】最佳团体
    TCP三次握手是什么?为什么要进行三次握手?两次,四次握手可以吗?
    TCP 和 UDP的最完整的区别
    素数环问题为什么不能是奇数?
    malloc、calloc、new的区别
    请实现两个函数,分别用来序列化和反序列化二叉树
    int* &p 讲解
    c++中常用容器讲解
  • 原文地址:https://www.cnblogs.com/mollnn/p/13578305.html
Copyright © 2011-2022 走看看