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); }