【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
??????????
*/