zoukankan      html  css  js  c++  java
  • bzoj2844

    http://www.lydsy.com/JudgeOnline/problem.php?id=2844

    线性基。。。

    先把线性基搞出来,然后不断逼近答案,如果这个基比答案小了,那么说明要加上,同时加上贡献:现在的位i +1<<(now-i) 为什么呢,我是这样理解的:一个数分两种情况:选这位和不选这位,如果前面选的位和当前q不同的话,那么前面已经统计过答案了,每次统计答案都是当已经选的数是q的一个子集。我们统计的答案是不选这个位,不选的话,肯定q小,那么这样的数有1<<(now-i)个,因为后面有now-i个基。

    然后还要+1,因为我们只统计了比这个数小的数的个数。还要乘上2^(n-now),因为前面now个数已经足够构成基底,那么后面n-now个数肯定会重复。这样会复制2^(n-now)个数。

    还有一种解释方法:因为后面都被消成0了,所以选不选都没关系,又因为后面每个a的组合都不一样,和前面搭配都不一样,所以可以。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 100010, mod = 10086;
    int n, now;
    ll q;
    ll a[N], bin[40];
    void gauss()
    {
        now = 1;
        for(int i = 30; i >= 0; --i)
        {
            int x = now;
            while(x <= n && !(a[x] & bin[i])) ++x; //没有这位
            if(x == n + 1) continue;
            swap(a[now], a[x]); // 消去这位其他的1
            for(int j = 1; j <= n; ++j) if(j != now && a[j] & bin[i]) a[j] ^= a[now]; 
            ++now;
        }
        --now;
    }
    int main()
    {
        bin[0] = 1; for(int i = 1; i <= 30; ++i) bin[i] = bin[i - 1] * 2;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        scanf("%d", &q);
        gauss();
        ll ans = 0, val = 0;
        for(int i = 1; i <= now; ++i) if((val ^ a[i]) <= q) 
        {
            val ^= a[i];
            ans += bin[now - i] % mod;
        }
        for(int i = 1; i <= n - now; ++i) ans = (ans << 1) % mod;
        ++ans;
        printf("%lld
    ", (ans % mod + mod) % mod); 
        return 0;
    }
    View Code
  • 相关阅读:
    lea
    DIV指令
    html基础
    浮点计算结果误差,以及解决方法
    java的threadLocal类
    java多线程基础总结
    sql反模式读书笔记 (持续更新)
    pdb 调试初步
    面向对象设计原则与总结 (持续更新)
    @servcie注解基本用法
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6836092.html
Copyright © 2011-2022 走看看