zoukankan      html  css  js  c++  java
  • Luogu P3526 [POI2011]OKR-Periodicity

    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=egin{cases}0&a_1=1\(a_1-1)*0+1&a_1>1end{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("");
        }
    }
    
  • 相关阅读:
    用Python写春联:抒写最真诚的祝福和最美好的祈愿
    python 注册表操作
    python 多参数
    arcgis tin版本转换使用复制tin
    python基础知识
    模型免费学习地址https://space.bilibili.com/378493128?spm_id_from=333.788
    在Python中用turtle函数画同心圆
    solr系统query检索词特殊字符的处理
    C#winform抓取百度,Google搜索关键词结果
    理解Solr缓存及如何设置缓存大小
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12294194.html
Copyright © 2011-2022 走看看