#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/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; }
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; }
原文地址:http://blog.csdn.net/vmurder/article/details/43448493