[BZOJ2844]线性基+xor本质不同第K大


  • 这道题仍然与子集异或和第k大有关,不过上次是给定k,让你求子集异或和本质不同的第k大是谁。这道题则是给定你一个数,问你它第一次出现的位置处于从小到大的第几个数。
  • 首先,它求的是位置,所以不能直接按照本质不同第k大那样求。我们需要先搞清楚,每一个权值会出现多少次。
  • 对于一个权值a,如何考虑它能出现多少次?显然有两种情况,一个是这个权值用去异或出0了,一个是它对0没啥卵用,而是和0异或仍然是自己。所以它这个权值出现的次数就是异或和为0的个数,即\(2^{n-cnt}\),cnt是线性基基底数量。
  • 那么我们现在只需要求有多少个本质不同的数小于q,然后乘上\(2^{n-cnt}\) 再+1就是答案了。
  • 具体求法其实和本质不同第k大类似,只不过每次是加2的幂次。

Coding(别忘了取模我这个sb)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=31;
const int mod=10086;
ll n,q,ans,cnt,now,a[50];
void insert(ll v){
    for(int i=MAXN;i>=0;--i) if((v>>i)&1){
        if(a[i]) v^=a[i];
        else{
            for(int j=i-1;j>=0;--j)
                if((v>>j)&1) v^=a[j];
            for(int j=i+1;j<=MAXN;++j)
                if((a[j]>>i)&1) a[j]^=v;
            a[i]=v;
            break;
        }
    }
}
int main(){
    scanf("%lld",&n);ll x;
    for(int i=1;i<=n;++i){
        scanf("%lld",&x);insert(x);
    }
    for(int i=0;i<=MAXN;++i) if(a[i]) cnt++;
    scanf("%lld",&q);ll tmp=cnt;
    for(int i=MAXN;i>=0;--i){
        if(a[i]){
            if((q>>i)&1){
                ans+=pow(2,tmp-1);
            }
            tmp--;
        }
    }
    for(int i=1;i<=n-cnt;++i) ans=ans*2%mod;
    printf("%lld\n",(ans+1)%mod);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kgxw0430/p/10425546.html