传送门:https://loj.ac/problem/6436
考虑没有问号的情况。
直接
k
m
p
kmp
kmp即可
由于
k
m
p
kmp
kmp不好处理
?
?
?间接矛盾的情况,我们直接讲用生成函数处理没有问号的情况的做法。
对于一个
b
o
r
d
e
r
border
border,如果前缀后缀首位置之差为
t
t
t,显然我们将一个串翻转后每一个位置赋值,再做卷积,那么一个
b
o
r
d
e
r
border
border对应的位置都会被卷到同一个位置。即对于原串中位置
i
,
j
(
i
<
j
)
i,j(i<j)
i,j(i<j),翻转后卷积会被卷到
i
+
n
−
j
i+n-j
i+n−j,即
n
−
(
j
−
i
)
n-(j-i)
n−(j−i)
即所有不同的
b
o
r
d
e
r
border
border会在卷积中根据
b
o
r
d
e
r
border
border首位置之差分类
我们考虑一个生成函数
在原串中
A
(
x
)
=
∑
i
=
1
n
[
s
[
i
]
=
=
′
1
′
]
x
i
A(x)=\sum_{i=1}^{n} [s[i] == '1']x^i
A(x)=∑i=1n[s[i]==′1′]xi
翻转后
B
(
x
)
=
∑
i
=
1
n
[
s
[
i
]
=
=
′
0
′
]
x
i
B(x) = \sum_{i=1}^{n} [s[i]=='0']x^i
B(x)=∑i=1n[s[i]==′0′]xi
如果没有问号,直接卷起来后判断某个位置是否有系数即可
考虑问号的情况
问号导致的矛盾必然是前缀后缀相交,
?
?
?出现在两个位置间接矛盾,如
1
=
?
=
0
1=?=0
1=?=0
考虑这种情况,显然这个
b
o
r
d
e
r
border
border如果满足条件必然也满足最小循环串
记 C ( x ) = A ( x ) B ( x ) C(x) =A(x)B(x) C(x)=A(x)B(x), C ( x ) C(x) C(x)中某个位置有值得含义即为某对长度为固定值的 ( 0 , 1 ) (0,1) (0,1)产生了矛盾。
可以发现 ? ? ?出现矛盾可以等价于通过最小循环串连接了一对矛盾的 ( 0 , 1 ) (0,1) (0,1)
也就是对于一个长度为
l
e
n
len
len的串
S
S
S,他的最小循环串长度为
x
=
n
−
l
e
n
x=n-len
x=n−len
那么通过
?
?
?矛盾当且仅当
x
∣
t
(
[
t
]
C
(
x
)
!
=
0
)
x|t([t]C(x)!=0)
x∣t([t]C(x)!=0)
F
F
T
FFT
FFT卷积做完之后直接对某个串暴力循环枚举倍数
复杂度
O
(
n
l
o
g
n
+
n
l
n
n
)
O(nlogn+nlnn)
O(nlogn+nlnn)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define Comp complex<double>
#ifdef M_pi
const double pi = M_pi;
#else
const double pi = acos(-1.0);
#endif
int len;
int n , m;
char s[501000];
Comp a[2001000] , b[2001000];
int r[2001000];
int flen;
int rd()
{
int sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(flag) return sum;
else return -sum;
}
void dft(Comp *a ,int f)
{
for(int i = 0; i < flen; ++i)
if(i < r[i]) swap(a[i], a[r[i]]);
for(int len = 2;len <= flen;len <<= 1)
{
Comp wn = Comp( cos(2 * pi / len) , f * sin(2 * pi / len));
for(int k = 0;k <= flen / len - 1;++k)
{
int st = k * len;
Comp w = 1;
for(int i = 0;i < (len>>1);++i)
{
Comp x = a[st + i],
y = a[st + i + len / 2] * w;
a[st + i] = x + y;
a[st + i + len / 2] = x - y;
w *= wn;
}
}
}
return;
}
bool flag[1001000];
void init(){
n = m = len-1;
for(int i = 0 ;i <= n;++i) a[i] = s[i+1] == '1';
for(int i = 0 ;i <= m;++i) b[i] = s[n-i+1] == '0';
flen = 1;
while( flen < (n + m + 1)) flen *= 2;
for(int i = n + 1;i < flen;++i) a[i] = 0;
for(int i = m + 1;i < flen;++i) b[i] = 0;
int l = log2(flen);
for(int i = 0;i < flen;++i)
r[i] = (r[i>>1]>>1)|((i&1)<<(l-1));
dft(a,1);
dft(b,1);
for(int i = 0;i < flen;++i) a[i] *= b[i];
dft(a,-1);
for(int i = 0;i <= n+m;++i)
{
int tmp = (int)(a[i].real()/flen + 0.5);
if(tmp != 0 && i < len) flag[len-(i+1)] = true;
if(tmp != 0 && i >= len) flag[(i+1)-len] = true;
}
return;
}
int main()
{
scanf("%s",s+1);len = strlen(s+1);
init();
ll ans = 1ll*len*len;
rep(i,1,len-1)
{
int tmp = len-i,now = tmp;
bool ck = true;
while(now <= len)
{
if(flag[now]) {ck = false;break;}
now += tmp;
}
if(ck)ans = ans^(1ll*i*i);
}
printf("%lld\n",ans);
return 0;
}