[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;}
原创粉丝点击