[atARC084F]XorShift

如果异或变为加法和减法,那么根据扩欧,$k$合法当且仅当$k|\gcd_{i=1}^{n}a_{i}$

换一种方式定义约数:$x$是$y$的约数当且仅当存在$p_{i}\in \{0,1\}$使得$\sum_{i=0}^{\infty}2^{i}x=y$,那么类似的,再把加法改为异或,我们就得到了本题中关于约数的定义

如何求$d=\gcd(x,y)$:假设$x$的最高位为$2^{p}$,$y$的最高位为$2^{q}$(二进制下,且不妨假设$p\ge q$),那么有$d|x$和$d|2^{p-q}y$,又因为$d|x$,所以$d|(x\oplus 2^{p-q}y)$,即$\gcd(x,y)=\gcd(y,x-2^{p-q}y)$

对于求gcd的过程,每一次必然会使得最高位-1,可以通过bitset优化到$o(\frac{nL^{2}}{64})$

令$d=\gcd_{i=1}^{n}a_{i}$,考虑$k\le C$等价于$k\oplus C$的最高位上的1是$C$的1或$k\oplus C$为0,因此枚举$k\oplus C$第一个非0的位置(通过$p_{i}$来控制),最后再判断所有$p_{i}$都确定了(即$k\oplus C$在$d$最高位即以上都为0时)能否即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 4005
 4 #define mod 998244353
 5 struct ji{
 6     int l;
 7     bitset<N>a;
 8 }m,a[11];
 9 int n,ans,mi[N];
10 char s[N];
11 void read(ji &a){
12     scanf("%s",s);
13     a.l=strlen(s);
14     for(int i=0;i<a.l;i++)a.a[a.l-i]=s[i]-'0';
15 }
16 ji gcd(ji x,ji y){
17     if (!y.l)return x;
18     x.a^=(y.a<<x.l-y.l);
19     while ((x.l)&&(!x.a[x.l]))x.l--;
20     if (x.l<y.l)swap(x,y);
21     return gcd(x,y);
22 }
23 void write(ji a){
24     for(int i=a.l;i;i--){
25         int p=a.a[i];
26         printf("%d",p);
27     }
28     printf("\n");
29 }
30 int main(){
31     mi[0]=1;
32     for(int i=1;i<N-4;i++)mi[i]=mi[i-1]*2%mod;
33     scanf("%d",&n);
34     read(m);
35     read(a[1]);
36     for(int i=2;i<=n;i++){
37         read(a[i]);
38         if (a[1].l<a[i].l)swap(a[1],a[i]);
39         a[1]=gcd(a[1],a[i]);
40     }
41     if (m.l<a[1].l){
42         printf("1");
43         return 0;
44     }
45     ji s=m;
46     for(int i=m.l;i>=a[1].l;i--){
47         if (m.a[i])ans=(ans+mi[i-a[1].l])%mod;
48         if (s.a[i])s.a^=(a[1].a<<i-a[1].l);
49     }
50     ans=(ans+1)%mod;
51     for(int i=a[1].l-1;i;i--)
52         if (s.a[i]){
53             if (!m.a[i])ans=(ans+mod-1)%mod;
54             break;
55         }
56     printf("%d",ans);
57 }
View Code

 

posted @ 2020-12-05 22:05  PYWBKTDA  阅读(159)  评论(0编辑  收藏  举报