[ARC084]F
来源:互联网 发布:mac pro 2017新款 编辑:程序博客网 时间:2024/05/29 19:15
题面
首先把一个二进制数ak,ak-1,..,a0看成多项式ak*x^k+ak-1 * x^( k-1) *… *a0,系数再模2意义下计算。
那么该数乘2相当于多项式*x,两个数xor相当于两个多项式相加。
所以我们定义gcd(P,Q)为多项式P和Q的最大公约数,计算方法如下:
设degP>=degQ(若degP< degQ则交换P,Q),deg表示次数,那么令P’=P+Q*(degP-degQ),就把P的最高次项消掉了,然后递归计算gcd(Q,P’),知道某一个为零,另一个多项式即是gcd。
这个gcd满足能用P,Q通过给定操作表示出来的多项式集合都和gcd的倍数多项式集合完全相同。(一个数H是gcd的倍数就是存在一个多项式H’使得H=H’*gcd),感性理解,倍数就相当于好几个gcd错位相加。。。
那么怎么判断一个多项式D是不是gcd的倍数,设一个多项式T初值为0,从最高位开始判端,如果某一位Di!=Ti,那么T就加上一个gcd*x^(i-deggcd),也就是gcd的最高位和Ti对齐,这样就使得Di=Ti,知道判断完deggcd这一位,后面的位都唯一确定了,只需判断0~deggcd-1位T和D相不相同即可。
所以计算<=上界X的gcd的倍数,确定deggcd~degX位上的数就有一个唯一答案,这些位< X的显然有X/x^(deggcd)个,只要判断一下这些位=X时后面的位是否<=X即可(<=则ans++)。
代码:
#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int mod=998244353;int n;bool r[7][4010],c[4010],g[4010],tmp[4010];void trans(char *s,bool *a){ int len=strlen(s)-1; for(int i=0;i<=len;i++) a[i]=s[len-i]-'0';}int deg(bool *a){ for(int i=4000;i>=0;i--) if(a[i]) return i;}void pls(bool *a,bool *b,int t){ for(int i=t;i<=4000;i++) a[i]=a[i]^b[i-t]; }void gcd(bool *a,bool *b,bool *d){ int da=deg(a),db=deg(b); if(da<db) swap(a,b),swap(da,db); if(db==0&&b[0]==0) {for(int i=0;i<=4000;i++) d[i]=a[i];return ;} pls(a,b,da-db); gcd(b,a,d);}int main(){ char cs[4010]; scanf("%d%s",&n,cs); trans(cs,c); int dc=deg(c); for(int i=1;i<=n;i++) { scanf("%s",cs); trans(cs,r[i]); } memset(g,0,sizeof(g)); for(int i=1;i<=n;i++) { for(int j=deg(g);j>=0;j--) tmp[j]=g[j]; gcd(r[i],tmp,g); } int dgcd=deg(g); memset(tmp,0,sizeof(tmp)); for(int i=dc;i>=dgcd;i--) if(tmp[i]^c[i]) pls(tmp,g,i-dgcd); int ans=0; for(int i=dc;i>=dgcd;i--) ans=((ans<<1)+c[i])%mod; for(int i=dgcd-1;i>=0;i--) if(tmp[i]<c[i]) break; else if(tmp[i]>c[i]) {ans--;break;} printf("%d",ans+1); return 0;}