BZOJ2728

来源:互联网 发布:mysql导入sql文件命令 编辑:程序博客网 时间:2024/06/07 00:42

这道题非常的神,第一步是看出NAND的性质:可以使用他来构造与非或这三种逻辑运算,这就很舒服。然后考虑两个数或的话,本质上是分成三个部分的(a&b,a-(a&b),b-(a&b)),所以我们可以尝试构造线性基,最后的答案只跟线性基里的元素或起来有关。所以说我们尝试枚举每一位,然后将所有数且起来,就得到这一位线性基的元素了,然后大概就可以像数位dp那样瞎算就完了

#include<cstdio>#include<algorithm>#include<cstring>const int N = 1005;int n, k, tt;long long l, r, a[N], use, S, ba[N], used;long long Solve (long long x) {    if (x < 0) return -1;    long long ret = 0, ans = 0;    for (int i = 1; i <= tt; ++i) if (ret + ba[i] <= x) {        ret += ba[i];        ans += 1ll << tt - i;    }    return ans;}int main () {    scanf("%d%d%lld%lld", &n, &k, &l, &r);    for (int i = 0; i < n; ++i) scanf("%lld", &a[i]);    for (int i = k - 1, j; ~i; --i) if (!(used >> i & 1)) {        for (j = 0, S = (1ll << i + 1) - 1; j < n; ++j) S &= (a[j] >> i & 1) ? a[j] : ~a[j];        used |= (ba[++tt] = S);    }    printf("%lld\n", Solve(r) - Solve(l - 1));    return 0;}