BZOJ2728
这道题非常的神,第一步是看出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;
}