給出A, B, C, 在1~A中找一個數x, 1~B中找一個數y, 使得x&y>C或x^y<C, 問這樣的二元組(x,y)有多少對.
原來數位dp可以這麼騷的...雖然大佬們說這是個裸題...
因爲^和&運算都是位運算, 所以把ABC都分爲2進製表示.
我們考慮最暴力的做法: 枚舉x, 枚舉y 判斷是不是滿足題意. 在這個過程中, 我們發現做了很多無用功, 例如, 如果x和y的高位&答案已經比C的高位要大, x和y的低位不論取什麼值不會影響結果, 反之亦然. 所以我們可以從高位向下數位dp, 每個位置保存x和y高位的大小信息. 這個題有趣在於數位dp不僅是關於一個數, 而是關於ABC三個數的. 其實只是在不斷的在枚舉A裏的x和B裏的y, C只是用來判斷答案. 兩個數當然會有兩個lim限制, 對於x和y不能取0, 所以要特別記錄x和y任意一個不能每一位全爲0.
What's New: 我的寫法是7維, 2維記錄lim, 2維記錄高位大小信息, 2維記錄全零情況.
實際上, 可以5維, 捨棄記錄全零的2維, 這樣算出來的是0~A選擇x, 0~B選擇y的答案, 利用容斥的思想, 把a設爲0, 答案減掉, 把a恢復, b設爲0, 再算一遍減掉, 再把0 0 的情況加上. 這樣, 我們無意中發現, 這樣的寫法可以解決這樣的題:
給出A1, A2, B1, B2, C, 在A1~A2中找一個數x, B1~B2中找一個數y, 使得x&y>C或x^y<C, 問這樣的二元組(x,y)有多少對.
通過這個題, 我發現, 數位dp不僅可以解決一個數有限制的問題, 還可以解決兩個數有限制的問題.
#include<bits/stdc++.h>
#define enter puts("")
using namespace std;
typedef long long ll;
inline ll read() {
ll x = 0;
int f = 0;
char ch = getchar();
while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x = f ? -x : x;
}
inline void write(ll x) {
if (x == 0) {
putchar('0');
return;
}
if (x < 0) {
putchar('-');
x = -x;
}
static char s[23];
int l = 0;
while (x != 0)s[l++] = x % 10 + 48, x /= 10;
while (l)putchar(s[--l]);
}
int _;
ll A, B, C;
int a[40], b[40], c[40];
ll dp[40][2][2][3][3][2][2];
// pos limA limB
// and a and b compare c: <:0 ==:1 >:2
// xor a and b compare c: <:0 ==:1 >:2
// 0: notZero 1:isAllZero
ll dfs(int pos, int limA, int limB, int andCmp, int xorCmp, int aIsZero, int bIsZero) {
if (pos <= 0)
return (andCmp == 2 || xorCmp == 0) && aIsZero == 0 && bIsZero == 0;
ll &ans = dp[pos][limA][limB][andCmp][xorCmp][aIsZero][bIsZero];
if (ans != -1)return ans;
ans = 0;
int mA = limA ? a[pos] : 1, mB = limB ? b[pos] : 1;
for (int i = 0; i <= mA; ++i) {
for (int j = 0; j <= mB; ++j) {
int nxtAndCmp, nxtXorCmp;
if (andCmp == 0)nxtAndCmp = 0;
else if (andCmp == 2)nxtAndCmp = 2;
else {
if ((i & j) == c[pos])nxtAndCmp = 1;
else if ((i & j) < c[pos])nxtAndCmp = 0;
else nxtAndCmp = 2;
}
if (xorCmp == 0)nxtXorCmp = 0;
else if (xorCmp == 2)nxtXorCmp = 2;
else {
if ((i ^ j) == c[pos])nxtXorCmp = 1;
else if ((i ^ j) < c[pos])nxtXorCmp = 0;
else nxtXorCmp = 2;
}
ans += dfs(pos - 1, limA && i == mA, limB && j == mB,
nxtAndCmp, nxtXorCmp, aIsZero && i == 0, bIsZero && j == 0);
}
}
return ans;
}
void init() {
_ = read();
while (_--) {
memset(dp, -1, sizeof(dp));
A = read(), B = read(), C = read();
int pos = 0;
while (pos < 33) {
a[++pos] = A & 1, b[pos] = B & 1, c[pos] = C & 1;
A >>= 1, B >>= 1, C >>= 1;
}
write(dfs(32, 1, 1, 1, 1, 1, 1));
enter;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
init();
return 0;
}