#include <stdio.h>
int main()
{
puts("转载请注明出处谢谢");
puts("http://blog.youkuaiyun.com/vmurder/article/details/43448493");
}
题意:给若干个数让你异或,然后询问第k大的异或和。
题解:
先搞出来线性基,然后第k大的异或和就是:
把k二进制拆分,第i位上有1,就把第i个线性基异或进来。
原因:
因为线性基是一堆高位上的1(或许有一些位动不了),然后把这样每一位可以填0/1,跟二进制差不多。
自己脑补去吧。
……我在说什么啊,我明白但是懒得写了。别管了,扒代码或者留言神马的吧。
经验之谈:
最开始写的是这份代码(WA):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
bool flag;
void EX_Ins(int n)
{
int i,j,k;
flag=0;
memset(ins,0,sizeof ins);
for(i=n;i;i--)
{
for(j=63;~j;j--)if((a[i]>>j)&1)
{
if(!ins[j])
{
ins[j]=a[i];
for(k=63;k>j;k--)
if((ins[k]>>j)&1)
ins[k]^=ins[j];
break;
}
else a[i]^=ins[j];
}
if(!a[i])flag=1;
}
return ;
}
int main()
{
freopen("test.in","r",stdin);
int i,g,_g;
unsigned long long k;
for(scanf("%d",&_g),g=1;g<=_g;g++)
{
printf("Case #%d:\n",g);
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%llu",&a[i]);
sort(a+1,a+n+1);
EX_Ins(n);
for(m=i=0;i<=63;i++)
{
if(ins[i])ins[m++]=ins[i];
}
for(scanf("%d",&n);n--;)
{
scanf("%llu",&k);
if(flag)k--;
if(k>>m)puts("-1");
else {
unsigned long long ret=0;
for(i=0;i<m;i++)if((k>>i)&1)
ret^=ins[i];
printf("%llu\n",ret);
}
}
}
return 0;
}
它WA了,请看这组数据:
1
3
77 89 53
1
7
为什么会WA呢?
我维护线性基的方法是先排个序从大到小往里面加,
然后这样出来一个线性基时就再对之前的线性基进行修改、、
然后就WA了。
貌似有理有据,但是错在了哪里呢?
嗯,一个大的数A可能被之前某个线性基异或一下,变成比之后的数更小的数了,
于是它的最高位上有个1,
然后之后某个初始值小的数B成为了线性基,但是它在数A那个线性基的那一位上有1,
然后自然就挂了~~
询问时就会有3<2的情况了(ins[1]^ins[2]<ins[2])
诶,233。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
bool flag;
void EX_Ins(int n)
{
int i,j,k;
flag=0;
memset(ins,0,sizeof ins);
for(i=n;i;i--)
{
for(j=63;~j;j--)if((a[i]>>j)&1)
{
if(!ins[j])
{
ins[j]=a[i];
for(k=0;k<63;k++)
for(int r=k+1;r<=63;r++)
if((ins[r]>>k)&1)
ins[r]^=ins[k];
break;
}
else a[i]^=ins[j];
}
if(!a[i])flag=1;
}
return ;
}
int main()
{
freopen("test.in","r",stdin);
int i,g,_g;
unsigned long long k;
for(scanf("%d",&_g),g=1;g<=_g;g++)
{
printf("Case #%d:\n",g);
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%llu",&a[i]);
// sort(a+1,a+n+1);
EX_Ins(n);
for(m=i=0;i<=63;i++)
{
if(ins[i])ins[m++]=ins[i];
}
for(scanf("%d",&n);n--;)
{
scanf("%llu",&k);
if(flag)k--;
if(k>>m)puts("-1");
else {
unsigned long long ret=0;
for(i=0;i<m;i++)if((k>>i)&1)
ret^=ins[i];
printf("%llu\n",ret);
}
}
}
return 0;
}