第一题
n个m位二进制,求异或值域总和。
【题解】异或值域--->使用线性基,解决去重问题。
m位二进制--->拆位,每位根据01数量可以用组合数快速统计总和。
#include<cstdio> #include<cstring> #include<cctype> #include<cmath> #include<bitset> #include<algorithm> #define ll long long using namespace std; int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t; } /*------------------------------------------------------------*/ const int inf=0x3f3f3f3f,maxn=410,MOD=1e9+7; int n,m,fac[maxn],fav[maxn],f2[maxn],sum,ans; char s[maxn]; bitset<maxn>a[maxn],b[maxn]; void gcd(int a,int b,int &x,int &y){ if(!b){x=1;y=0;} else{gcd(b,a%b,y,x);y-=x*(a/b);} } int inv(int a){ int x,y; gcd(a,MOD,x,y); return ((x%MOD)+MOD)%MOD; } int C(int n,int m){return 1ll*fac[n]*fav[m]%MOD*fav[n-m]%MOD;} int main(){ n=read();m=read(); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=m;j++)a[i][m-j]=s[j]-'0'; for(int j=m-1;j>=0;j--)if(a[i][j]){ if(b[j]==0){b[j]=a[i];break;} else a[i]^=b[j]; } } int sum0,sum1; fac[0]=1;for(int i=1;i<=m;i++)fac[i]=1ll*fac[i-1]*i%MOD; for(int i=0;i<=m;i++)fav[i]=inv(fac[i]); f2[0]=1;for(int i=1;i<=m;i++)f2[i]=1ll*f2[i-1]*2%MOD; ans=0; for(int i=0;i<m;i++){ sum0=sum1=sum=0; for(int j=0;j<m;j++)if(b[j]!=0){ if(b[j][i]==0)sum0++;else sum1++; for(int j=1;j<=sum1;j+=2)sum=(sum+C(sum1,j))%MOD; ans=(ans+1ll*f2[i]*sum%MOD*f2[sum0]%MOD)%MOD; } printf("%d",ans); return 0; }