题面
题解
考虑一个完美串 s s s 应该满足什么性质。
若 s s s 中 0 0 0 和 1 1 1 数量相同,那么显然是 01 01 01 交错的。
否则不妨设 1 1 1 比 0 0 0 多,那么循环意义下一定有连续的 11 11 11,不然 1 1 1 不可能比 0 0 0 多。
又由于有连续的 11 11 11,那么就不能有连续的 00 00 00,不然这个串就不是完美串。
考虑一个 1 1 1 比 0 0 0 多的完美串 s s s,那么在循环意义下, s s s 可以被分割成若干段 1 1 1,而且每段 1 1 1 之间恰好隔着一个 0 0 0。
从 s s s 的每段 1 1 1 中删去一个 1 1 1 得到一个新的字符串 t t t,容易证明 s s s 是完美串当且仅当 t t t 是完美串。
0 0 0 比 1 1 1 多的情况同理。
那么假设 s s s 中有 x x x 个 0 0 0, y y y 个 1 1 1。这个过程其实相当于 ( x , y ) → ( x − y , y ) (x,y)\to(x-y,y) (x,y)→(x−y,y) 或 ( x , y ) → ( x , y − x ) (x,y)\to (x,y-x) (x,y)→(x,y−x),也就是辗转相减的过程,而辗转相减可以优化成辗转相除。
如果我们枚举一开始长度为 n n n 的完美串 s s s 中有 i i i 个 0 0 0, n − i n-i n−i 个 1 1 1 的话,其实我们是可以模拟这个辗转相除的过程的。也就是说,我们可以从最后的串倒推回来 s s s 长什么样。
那么我们一个一个把倒推回来的串 s s s 和题目给的串比较,看是否匹配就行了。
用 bitset
优化匹配可以做到
O
(
n
3
w
)
O(\dfrac{n^3}{w})
O(wn3) 的时间复杂度。
代码如下:
#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
??????????
*/