【HDU3949】XOR 線性基
阿新 • • 發佈:2018-12-24
#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; }
它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; }