题目概述
给出 nn 个数,求选出的非空集合中异或和第 小的异或和(异或和相同算一次),没有 kk 个输出 。
解题报告
如果构造线性基时将矩阵消成对角矩阵,得到的线性基就有一个很棒的性质:最高位为 ii 的数至多只有一个,且其他数第 i 位为 (即使得到的线性基无法表示为对角矩阵,只要按照消成对角矩阵的方法去构造,也满足这个性质)。
因为最高位为 ii 的数至多只有一个,所以挑出矩阵中的非零项 , ∑m−1i=0Bi(k and 2i)∑i=0m−1Bi(k and 2i) 就是答案。
解题报告
#include<cstdio>
#include<cstring>
typedef long long LL;
using namespace std;
const int Log=60;
int te,n,Q;LL M[Log],B[Log];
inline void Insert(LL x){
for (int j=Log;~j;j--)
if (x>>j&1)
if (M[j]) x^=M[j]; else{
M[j]=x;for (int k=0;k<j;k++) if (M[j]>>k&1) M[j]^=M[k];
for (int k=j+1;k<Log;k++) if (M[k]>>j&1) M[k]^=M[j];break;
}
}
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (int i=(scanf("%d",&te),1);i<=te;i++){
printf("Case #%d:\n",i);scanf("%d",&n);memset(M,0,sizeof(M));B[0]=0;
for (int i=1;i<=n;i++) {LL x;scanf("%lld",&x);Insert(x);}
for (int i=0;i<Log;i++) if (M[i]) B[++B[0]]=M[i];
for (scanf("%d",&Q);Q;Q--){
LL x,ans=0;int pos=0;scanf("%lld",&x);x-=B[0]<n;
while (x) {pos++;if (x&1) ans^=B[pos];x>>=1;}
if (B[0]<pos) puts("-1"); else printf("%lld\n",ans);
}
}
return 0;
}

本文介绍了一种解决特定组合数学问题的高效算法——找出一组数字中所有非空子集的异或和中第K小的值。通过构建线性基并利用位运算特性,该算法能在较短时间内找到解决方案。若不存在足够数量的有效子集,则返回特殊值-1。
348

被折叠的 条评论
为什么被折叠?



