牛客 19多校7 H 數位dp

給出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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章