第一题

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;
}
View Code

相关文章:

  • 2021-12-06
  • 2021-11-07
  • 2021-08-05
  • 2021-10-23
  • 2021-11-25
  • 2021-11-25
  • 2021-05-18
  • 2022-12-23
猜你喜欢
  • 2021-10-11
  • 2021-11-19
  • 2021-04-14
  • 2021-04-13
  • 2021-06-02
  • 2022-12-23
  • 2021-11-21
相关资源
相似解决方案