把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷3526】[POI2011] OKR-Periodicity(border)

点此看题面

  • 给定一个长度为\(n\)的字符串,求长度为\(n\)的字典序最小的\(01\)串,满足它们的周期集合相同。
  • 数据组数\(\le20\)\(n\le2\times10^5\)

\(border\)性质

众所周知,一个长度为\(n\)的字符串有长度为\(k\)的周期等价于有长度为\(n-k\)\(border\)

所以我们先利用\(KMP\)求出这个字符串的\(border\)集合,那么问题就变成要构造一个\(01\)串与它的\(border\)集合相同。

首先考虑如何构造长度最小的那个\(border\)(设为\(p_{\min}\)),若\(p_{\min}=1\)就是一个\(\texttt{"0"}\),否则是\(p_{\min}-1\)\(\texttt{"0"}\)后面跟上一个\(\texttt{"1"}\)

然后考虑如何从\(p_{lst}\)\(p_{now}\)扩展答案,分类讨论:

  • 如果\(2p_{lst}\ge p_{now}\),直接把原本答案串的最后\(p_{now}-p_{lst}\)个字符复制一份即可。
  • 如果\(2p_{lst}<p_{now}\),最好的情况当然是首尾填\(p_{lst}\),中间放\(p_{now}-2p_{lst}\)\(\texttt{"0"}\),但这样可能会产生不应存在的周期。发现\(p_{lst}+(p_{now}-2p_{lst})\times\texttt{"0"}+p_{lst}\)有不应存在的周期等价于\(p_{lst}+(p_{now}-2p_{lst})\times\texttt{"0"}\)有长度为\(m=p_{now}-p_{lst}\)约数的周期,也就是说\(m-nxt_m\)\(m\)的约数。此时,只要把最后一个\(\texttt{"0"}\)改成\(\texttt{"1"}\)即可。

我们只要实时维护好答案串的\(nxt\)数组即可。

代码:\(O(Tn)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 200000
using namespace std;
int n,p[N+5];char s[N+5];
int m,nxt[N+5];char g[N+5];I void A(Cn char& x)//在末尾添加一个字符
{
	if(g[++m]=x,m==1) return;RI i=nxt[m-1];W(i&&g[i+1]^x) i=nxt[i];nxt[m]=i+(g[i+1]==x);//求nxt
}
int main()
{
	RI Tt,i,t;scanf("%d",&Tt);W(Tt--)
	{
		for(scanf("%s",s+1),n=strlen(s+1),m=0,i=1;i<=n;++i) A(s[i]);for(t=0,i=n;i;i=nxt[i]) p[++t]=i;//求出原串所有border
		if(m=0,p[t]^1) {for(i=1;i^p[t];++i) A('0');A('1');}else A('0');W(--t)//求出初始答案串
		{
			if(2*p[t+1]>=p[t]) {for(i=p[t+1]-(p[t]-p[t+1])+1;i<=p[t+1];++i) A(g[i]);continue;}//直接把最后p[t]-p[t+1]个字符复制一份
			for(i=1;i<=p[t]-2*p[t+1];++i) A('0');!(m%(m-nxt[m]))&&(--m,A('1'),0);for(i=1;i<=p[t+1];++i) A(g[i]);//检验能否在中间放p[t]-2*p[t+1]个0,不行则把最后的0改成1
		}g[n+1]=0,puts(g+1);
	}return 0;
}
posted @ 2021-07-19 16:18  TheLostWeak  阅读(86)  评论(0编辑  收藏  举报