首页 > 代码库 > BZOJ 2844 albus就是要第一个出场 高斯消元
BZOJ 2844 albus就是要第一个出场 高斯消元
题目大意:给定一个n个数的集合S和一个数x,求x在S的2^n个子集从大到小的异或和序列中最早出现的位置
有学长真好不用自己打题目大意了233
首先我们求出线性基 我们会得到一些从大到小排列的数和一堆0 记录0的个数
不考虑0,看前面的数,由于线性基的性质,我们直接贪心从大到小枚举 若当前异或和异或这个值小于Q则取这个数 (注意^不要写成+或者| 本蒟蒻已经因为这个WA了两道题了
然后我们通过每个数取不取可以得到一个01序列 这个序列就是通过异或可以得到的小于Q的数的数量的二进制
比如线性基是8 4 2 Q=13 取完8和4之后无法法取2 那么得到的01序列就是110 即6
然后我们再加上空集的0
然后考虑后面的0 设有m个0 那么每个数出现的次数为2^m 乘起来后+1就是答案
一个细节就是当Q=0的时候计算小于Q的数的数量时不要算上0 不懂的可以自己测测0
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 #define Mo 10086 using namespace std; int n,m,q,ans,a[M]; void Gaussian_Elimination() { int i,j,k=0; for(j=1<<30;j;j>>=1) { for(i=k+1;i<=n;i++) if(a[i]&j) break; if(i==n+1) continue; swap(a[i],a[++k]); for(i=1;i<=n;i++) if(i!=k) if(a[i]&j) a[i]^=a[k]; } m=n-k; n=k; } int ksm(int x,int y) { int re=1; while(y) { if(y&1)re*=x,re%=Mo; x*=x,x%=Mo; y>>=1; } return re; } int main() { int i,num,now=0; cin>>n; for(i=1;i<=n;i++) scanf("%d",&a[i]); Gaussian_Elimination(); cin>>q; for(i=1;i<=n;i++) if( (now^a[i])<q ) ans+=ksm(2,n-i),ans%=Mo,now^=a[i]; if(q) ++ans,ans%=Mo; ans*=ksm(2,m),ans%=Mo; ++ans,ans%=Mo; cout<<ans<<endl; }
BZOJ 2844 albus就是要第一个出场 高斯消元
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。