【XSY3947】完美串(思维_结论)

题面

完美串

题解

考虑一个完美串 \(s\) 应该满足什么性质。

\(s\)\(0\)\(1\) 数量相同,那么显然是 \(01\) 交错的。

否则不妨设 \(1\)\(0\) 多,那么循环意义下一定有连续的 \(11\),不然 \(1\) 不可能比 \(0\) 多。

又由于有连续的 \(11\),那么就不能有连续的 \(00\),不然这个串就不是完美串。

考虑一个 \(1\)\(0\) 多的完美串 \(s\),那么在循环意义下,\(s\) 可以被分割成若干段 \(1\),而且每段 \(1\) 之间恰好隔着一个 \(0\)

\(s\) 的每段 \(1\) 中删去一个 \(1\) 得到一个新的字符串 \(t\),容易证明 \(s\) 是完美串当且仅当 \(t\) 是完美串。

\(0\)\(1\) 多的情况同理。

那么假设 \(s\) 中有 \(x\)\(0\)\(y\)\(1\)。这个过程其实相当于 \((x,y)\to(x-y,y)\)\((x,y)\to (x,y-x)\),也就是辗转相减的过程,而辗转相减可以优化成辗转相除。

如果我们枚举一开始长度为 \(n\) 的完美串 \(s\) 中有 \(i\)\(0\)\(n-i\)\(1\) 的话,其实我们是可以模拟这个辗转相除的过程的。也就是说,我们可以从最后的串倒推回来 \(s\) 长什么样。

那么我们一个一个把倒推回来的串 \(s\) 和题目给的串比较,看是否匹配就行了。

bitset优化匹配可以做到 \(O(\dfrac{n^3}{w})\) 的时间复杂度。

代码如下:

#include<bits/stdc++.h>

#define un unsigned
#define N 1050

using namespace std;

namespace modular
{
	const int mod=1000000007;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

const un int base=1145141;

int n,ans;
int a[N],b[N];
char s[N];

bitset<N>now,ss,vis;

int work(int x,int y,bool opt)
{
	if(!y)
	{
		for(int i=1;i<=x;i++) a[i]=opt;
		return x;
	}
	int t=x/y;
	int d=work(y,x-y*t,opt^1);
	int nn=y+x-y*t;
	int cnt=0;
	for(int i=1;i<=nn;i++)
	{
		if(a[i]!=opt)
			for(int j=1;j<=t;j++)
				b[++cnt]=opt;
		b[++cnt]=a[i];
	}
	for(int i=1;i<=x+y;i++) a[i]=b[i];
	return d;
}

void solve(int d)
{
	now.reset();
	for(int i=1;i<=n;i++)
		if(a[i]) now.set(i);
	if((now&vis)==ss) ans++;
	for(int i=1;i<d;i++)
	{
		bool t=now[1];
		now[1]=0;
		now>>=1;
		if(t) now.set(n);
		if((now&vis)==ss) ans++;
	}
}

int main()
{
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]!='?')
		{
			ss.set(i,s[i]-'0');
			vis.set(i,1);
		}
	}
	for(int i=0;i<=n;i++)
	{
		int d;
		if(i<n-i) d=work(n-i,i,1);
		else d=work(i,n-i,0);
		solve(n/d);
	}
	printf("%d\n",ans);
	return 0;
}
/*
4
?01?
*/
/*
10
??????????
*/
posted @ 2022-10-30 14:26  ez_lcw  阅读(21)  评论(0编辑  收藏  举报