1. 程式人生 > >【BZOJ 2844】: albus就是要第一個出場

【BZOJ 2844】: albus就是要第一個出場

數組 str 一次 長度 log -c 一個 names 一個數

題目大意:

  給一個長度為n的序列,將其子集的異或值排序得到B數組,給定一個數字Q,保證Q在B中出現過,詢問Q在B中第一次出現的下標。

題解:

  感覺和hdu3949第K小異或值有一像,然而發現要求出現次數……emmmm

  考慮線性基的性質,即在n個數字中求出其極大線性無關子集,設其長度為m,也就意味著有n-m個元素是可以用這m個元素表示的,考慮假設我們現在用這m個變量表示出了一個數字A,那麽給A異或上0還是其本身,考慮剩下的n-m個元素可以湊多少個0,即二項式定理,所以可以知道,對於任意一個可以用線性基表示出來的數,其出現次數均為$2^{n-m}$。

代碼:

 1 #include "bits/stdc++.h"
 2 
 3 using namespace std;
 4 
 5 inline int read(){
 6     int s=0,k=1;char ch=getchar();
 7     while(ch<0|ch>9) ch==-?k=-1:0,ch=getchar();
 8     while(ch>47&ch<=9) s=s*10+(ch^48),ch=getchar();
 9     return s*k;
10 }
11 
12 const int N=1e5+5
,mod=10086; 13 14 int a[N],bin[100],b[100],n,Q,m,cnt,ans; 15 16 inline int powmod(int a,int b){ 17 int ret=1; 18 while(b){ 19 if(b&1) ret=ret*a%mod; 20 b>>=1,a=a*a%mod; 21 }return ret; 22 } 23 24 int main(){ 25 n=read(); 26 register int i,j,k;
27 for(i=1;i<=n;++i) a[i]=read(); 28 for(i=0;i<=30;++i)bin[i]=1<<i; 29 for(i=1;i<=n;++i) 30 for(j=30;~j;--j) if(a[i]&bin[j]) 31 if(b[j]) a[i]^=b[j]; 32 else { 33 b[j]=a[i];++cnt; 34 for(k=j-1;~k;--k) if(b[k]&&(b[j]&bin[k])) b[j]^=b[k]; 35 for(k=j+1;k<=30;++k) if(b[k]&bin[j]) b[k]^=b[j]; 36 break; 37 } 38 for(i=0;i<=30;++i) if(b[i]) a[m++]=i; 39 Q=read(); 40 for(i=0;i^m;++i) if(Q&bin[a[i]]) 41 ans|=bin[i]; 42 ans%=mod; 43 printf("%d\n",(ans*powmod(2,n-cnt)%mod+1)%mod); 44 }

【BZOJ 2844】: albus就是要第一個出場