time limit per test : 2 seconds
memory limit per test : 256 megabytes
分数:2100 // 虽然我觉得思维难度还挺高的,像是2500的题,不像普通的2100那么简单
After learning about polynomial hashing, Heidi decided to learn about shift-xor hashing. In particular, she came across this interesting problem.
Given a bitstring y ∈ { 0 , 1 } n y∈ \{0,1\} ^n y∈{0,1}n find out the number of different k ( 0 ≤ k < n ) k (0≤k<n) k(0≤k<n) such that there exists x ∈ { 0 , 1 } n x∈\{0,1\}^n x∈{0,1}n for which y = x ⊕ s h i f t k ( x ) y=x⊕shift^k(x) y=x⊕shiftk(x).
In the above, ⊕ is the xor operation and shiftk is the operation of shifting a bitstring cyclically to the right k times. For example, 001⊕111=110
and shift3(00010010111000)=00000010010111
.
Input
The first line contains an integer n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^5) n(1≤n≤2⋅105), the length of the bitstring y y y.
The second line contains the bitstring y y y.
Output
Output a single integer: the number of suitable values of k k k.
Example
Input
4
1010
Output
3
Note
In the first example:
1100⊕shift1(1100)=1010
1000⊕shift2(1000)=1010
0110⊕shift3(0110)=1010
There is no x x x such that x⊕x=1010
, hence the answer is 3.
题意:
给一个长度为n的01串 y y y,问有多少个 k ( 0 < = k < n ) k(0<=k<n) k(0<=k<n)满足存在一个长度为n的01串x使得 x ⊕ s h i f t k ( x ) = y x⊕shift^k(x) = y x⊕shiftk(x)=y
s h i f t k ( x ) shift^k(x) shiftk(x)操作是将字符串x向右循环位移 k k k位。
题解:
考虑位移k的情况
显然字符串满足以下等式
x[1]^x[1+k]=y[1]
x[2]^x[2+k]=y[2]
...
x[n]^x[k]=y[n]
将等式拆分:
//对于所有i<=k都满足如下情况
x[i]^x[i+k]=y[i]
x[i+k]^x[i+2*k]=y[i+k]
...
可以发现对于所有的 g c d ( n , u ) = k gcd(n,u) = k gcd(n,u)=k的情况,都符合上面的方程组
将方程组化简可得:
y[i]^y[i+k]^y[i+2*k]^.... = x[i]^x[i+k]^x[i+k]^.....(相邻两两相消) = 0
那么我们可以预处理出所有 g c d ( n , i ) gcd(n,i) gcd(n,i)是否能够成为解,最后直接枚举 k k k统计答案即可。
#include
#define ll long long
using namespace std;
const int MAXN=200004;
int ok[MAXN],l;
char s[MAXN];
void work(int base){
for(int i=1;i<=base;i++){
ll sum=0;
for(int j=i;j<=l;j+=base){
sum^=(s[j]-'0');
}
if(sum)return ;
}
ok[base]=1;
}
int main(){
scanf("%d",&l);
scanf("%s",s+1);
memset(ok,0,sizeof(ok));
bool flag=0;
for(int i=1;i<=l;i++){
if(s[i]=='1')flag=1;
}
if(!flag)ok[0]=1;
for(int k=1;k*k<=l;k++){
if(l%k==0){
work(k);
work(l/k);
}
}
int ans=0;
if(!flag)ans++;
for(int k=1;k<l;k++){
ans+=ok[__gcd(l,k)];
}
printf("%d\n",ans);
return 0;
}