码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P3526 [POI2011]OKR-Periodicity

时间:2020-02-11 11:51:28      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:wap   排序   puts   实时   void   int   一个   tchar   period   

Link
存在一个\(m\)的period\(\Leftrightarrow\)存在一个长度为\(n-m\)的border。
因此对于字符串\(s\),我们处理出它的border集合(包含\(n\)),并将其升序排序。
假设\(s\)的border集合为\(a_1,\cdots,a_m\)
那么我们有一个很自然的想法:
先构造出满足border集合为\(\{a_1\}\)的长度为\(a_1\)的字典序最小的01串\(s_1\)
然后构造出满足border集合为\(\{a_1,a_2\}\)的长度为\(a_2\)的字典序最小的01串\(s_2\)
。。。
构造出border集合为\(\{a_1\}\)的长度为\(a_1\)的字典序最小的01串\(s_1\)是很容易的:
\(s_1=\begin{cases}0&a_1=1\\(a_1-1)*0+1&a_1>1\end{cases}\)
然后我们考虑如何已知border集合为\(\{a_1,\cdots,a_{i-1}\}\)的长度为\(a_{i-1}\)的字典序最小的01串\(s_{i-1}\)求出border集合为\(\{a_1,\cdots,a_i\}\)的长度为\(a_i\)的字典序最小的01串\(s_i\)
让我们分几种情况讨论:
\(1.2a_{i-1}\ge a_i\)
我们只需要将\(s_{i-1}\)的后\(a_i-a_{i-1}\)位复制并接在\(s_{i-1}\)的后面即可得到\(s_i\)
\(2.2a_{i-1}<a_i\)
首先\(s_{i-1}\)一定会在\(a_i\)的头尾出现两次。
然后我们有一个很简单的想法是中间填\(a_i-2a_{i-1}\)0
但是这样可能会多出来一些其它的border。
因此先让\(s_i=s_{i-1}+(a_i-2a_{i-1})*0\),然后检查此时\(s_i\)是否存在一个长度为\(a_i-a_{i-1}\)的约数的period。
如果存在那么我们再接一个\(s_{i-1}\)到后面就会产生不合法的border,因此我们先把当前\(s_i\)的最后一个字符替换成1再把\(s_{i-1}\)接在后面。
如果不存在那么我们直接把\(s_{i-1}\)接在后面就行了,这样并不会产生不合法的border。
注意到\(s_i=s_{i-1}+???\),并且删除末尾字符的总量是\(O(n)\)的。
因此我们预处理出\(s\)的next数组,然后实时维护\(s_i\)的next数组即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=200007;
char str[N],ans[N];
int T,n,m,p,next[N],a[N],fail[N];
void ins(int c)
{
    ans[++p]=c;
    if(p>1)
    {
    for(fail[p]=fail[p-1];fail[p]&&ans[fail[p]+1]^ans[p];fail[p]=fail[fail[p]]);
    fail[p]+=ans[fail[p]+1]==ans[p];
    }
}
int main()
{
    for(scanf("%d",&T);T;--T)
    {
    scanf("%s",str+1),n=strlen(str+1);
    for(int i=2,k=0;i<=n;next[i]=k+=str[k+1]==str[i],++i) while(k&&str[k+1]^str[i]) k=next[k];
    a[m=0]=p=0;
    for(int i=n;i;i=next[i]) a[++m]=i;
    for(int i=1;i<=m/2;++i) std::swap(a[i],a[m+1-i]);
    if(a[1]==1) ins(0);
        else
    {
        for(int i=1;i<a[1];++i) ins(0);
        ins(1);
    }
        for(int i=2;i<=m;++i)
    {
            if(a[i-1]*2>=a[i]) for(int j=a[i-1]+1,k=a[i]-a[i-1];j<=a[i];++j) ins(ans[j-k]);
        else
        {
                for(int j=a[i]-2*a[i-1];j;--j) ins(0);
                if(!(p%(p-fail[p]))) --p,ins(1);
                for(int j=1;j<=a[i-1];++j) ins(ans[j]);
            }
        }
    for(int i=1;i<=n;++i) putchar(ans[i]+'0');
    puts("");
    }
}

Luogu P3526 [POI2011]OKR-Periodicity

标签:wap   排序   puts   实时   void   int   一个   tchar   period   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12294194.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!