G63 线性基 异或和的方案数 P3857 [TJOI2008] 彩灯

视频链接:G63 线性基 异或和的方案数 P3857 [TJOI2008] 彩灯_哔哩哔哩_bilibili

 

 

P3857 [TJOI2008] 彩灯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

// 线性基 O(55*n)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define LL long long
const int N=60,mod=2008;
int n,m,k;
LL a[N];

void gauss(){
  for(int i=55;i>=0;i--){
    for(int j=k;j<m;j++)
      if(a[j]>>i&1){swap(a[j],a[k]); break;}
    if((a[k]>>i&1)==0) continue;
    for(int j=0;j<m;j++)
      if(j!=k&&(a[j]>>i&1)) a[j]^=a[k];
    k++; if(k==m) break;
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=0;i<m;i++){
    char s[N]; scanf("%s",s);
    LL x=0;
    for(int j=0;j<strlen(s);j++)
      x+=(1ll<<(n-j))*(s[j]=='O');
    a[i]=x;
  }
  gauss();
  printf("%lld\n",(1ll<<k)%mod);
}

 

P4869 albus就是要第一个出场 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

结论:n 个数组成大小为 k 的线性基,则能构成 2^k 种不同的数,每个数出现 2^(n-k) 次
思路:先用线性基求出在不同异或和中的排名 rk,再用快速幂求出出现次数,乘积+1 即答案

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int mod=10086;
int n,q,k,rk;
int p[35];

int qpow(int a,int b){ //快速幂
  int res=1;
  while(b){
    if(b&1) res=(res*a)%mod;
    a=(a*a)%mod;
    b>>=1;
  }
  return res;
}
void insert(int x){ //贪心法
  for(int i=30;i>=0;--i){
    if(x>>i&1){
      if(!p[i]){
        p[i]=x; break;
      }
      x^=p[i];
    }    
  }
}
int main(){
  scanf("%d",&n);
  for(int i=1,x;i<=n;++i)
    scanf("%d",&x),insert(x);
  scanf("%d",&q);
  for(int i=0;i<=30;i++){
    if(p[i]){
      if(q>>i&1) rk+=1<<k;
      k++;
    }
  }
  printf("%d\n",(1ll*rk*qpow(2,n-k)+1)%mod);
}

 

posted @ 2024-07-03 21:41  董晓  阅读(55)  评论(0编辑  收藏  举报