bzoj2844 albus就是要第一个出场
这个题有了hdu3949那个题的基础就非常好做了,因为这两个题求得东西是对偶的....
这次我们要求某个数是第几个出现的(不去重),那么我们只要知道它去重的排名,再乘上每个数重复的个数(2n-m),加上1就好了。
还是高斯消元,不过要注意的是这里的高斯消元和普通的解xor线性方程还不一样,因为我们是要得到一组基数,代表从高到低的一些二进制位,所以我们要从最高位的元开始找,并且消的时候是对所有方程消元。注意我们是对数消元,用尽量少的数去代表尽量多的二进制位,所以这样消可以尽量地避免重复。
最后求答案的时候,只要类似倍增地从大到小试,如果这位能取1就取,最后就得到了需要的排名。
albus
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 122000 7 #define inf 1000000000 8 #define ms 10086 9 #define bit 31 10 using namespace std; 11 typedef long long LL; 12 int a[maxn]; 13 int n,m,ask; 14 LL num,rank; 15 16 void gauss(int n) 17 { 18 int k=1; 19 for (int i=bit;i;i--) 20 { 21 int p=0; 22 for (int j=k;j<=n;j++) if ((a[j]>>(i-1))&1) { p=j; break; } 23 if (p) 24 { 25 swap(a[p],a[k]); 26 for (int j=1;j<=n;j++) if (j!=k&&(a[j]>>(i-1))&1) a[j]^=a[k]; 27 k++; 28 } 29 } 30 m=k-1; 31 } 32 LL po(LL a,int b) 33 { 34 LL tmp=1; 35 while (b) 36 { 37 if (b&1) tmp=tmp*a%ms; 38 b=b/2; 39 a=a*a%ms; 40 } 41 return tmp; 42 } 43 44 int main() 45 { 46 scanf("%d",&n); 47 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 48 scanf("%d",&ask); 49 gauss(n); 50 //for (int i=1;i<=n;i++) 51 //{ 52 // for (int j=1;j<=bit;j++) 53 // cout<<((a[i]>>(j-1))&1)<<' '; 54 // cout<<endl; 55 //} 56 num=po(2,n-m); 57 rank=0; 58 for (int i=1;i<=m;i++) 59 if ((ask^a[i])<ask) 60 { 61 ask^=a[i]; 62 rank|=(1<<(m-i)); 63 } 64 LL ans=num*rank%ms+1; 65 printf("%lld\n",ans); 66 return 0; 67 }
AC without art, no better than WA !