标签:cst uil turn stdin ase main mem 插入 query
给你n个数,问你将它们取任意多个异或起来以后,所能得到的第K小值?
求出线性基来以后,化成简化线性基,然后把K二进制拆分,第i位是1就取上第i小的简化线性基即可。注意:倘若原本的n个数两两线性无关,也即线性基的大小恰好为n时,异或不出零,否则能异或出零,要让K减去1。
这也是线性基的模板。
#include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll d[64],p[64]; int cnt;//简化线性基的大小 bool Insert(ll val){//尝试插入线性基,返回是否插入成功 for(int i=62;i>=0;--i){ if(val&(1ll<<i)){ if(!d[i]){ d[i]=val; break; } val^=d[i]; } } return val>0; } ll QueryMax(){ ll res=0; for(int i=62;i>=0;--i){ if((res^d[i])>res){ res^=d[i]; } } return res; } ll QueryMin(){ for(int i=0;i<=62;++i){ if(d[i]){ return d[i]; } } return 0; } void Rebuild(){//化为简化线性基 for(int i=62;i>=0;--i){ for(int j=i-1;j>=0;--j){ if(d[i]&(1ll<<j)){ d[i]^=d[j]; } } } for(int i=0;i<=60;++i){ if(d[i]){ p[cnt++]=d[i]; } } } int T,n,m; ll Kth(ll K){ if(cnt<n){ --K;//如果并非原本的n个数都线性无关的话,那么是能异或出零的 } ll res=0; if(K>=(1ll<<cnt)){ return -1ll; } for(int i=60;i>=0;--i){ if(K&(1ll<<i)){ res^=p[i]; } } return res; } int main(){ // freopen("hdu3949.in","r",stdin); ll x; scanf("%d",&T); for(int zu=1;zu<=T;++zu){ memset(d,0,sizeof(d)); memset(p,0,sizeof(p)); cnt=0; printf("Case #%d:\n",zu); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%lld",&x); Insert(x); } Rebuild(); scanf("%d",&m); for(;m;--m){ scanf("%lld",&x); printf("%lld\n",Kth(x)); } } return 0; }
标签:cst uil turn stdin ase main mem 插入 query
原文地址:http://www.cnblogs.com/autsky-jadek/p/7508067.html