当前位置: 代码迷 >> 综合 >> Codeforces Round 597 (Div. 2)___F Daniel and Spring Cleaning —— 数位DP
  详细解决方案

Codeforces Round 597 (Div. 2)___F Daniel and Spring Cleaning —— 数位DP

热度:7   发布时间:2024-01-09 10:51:30.0

题目链接:点我啊╭(╯^╰)╮

题目大意:

    给出 l , r l,r lr
    问满足以下条件的 ( a , b ) (a,b) (a,b) 有多少对
    在这里插入图片描述

解题思路:

     a + b = a ? b a+b = a \bigoplus b a+b=a?b      = > => =>      a a a & \& & b = 0 b = 0 b=0
    证明: a ? b a \bigoplus b a?b为没有进位的二进制加法, a + b a+b a+b 为有进位的
    则若满足 a + b = a ? b a+b = a \bigoplus b a+b=a?b,则一定满足 a a a & \& & b = 0 b = 0 b=0

    然后开始数位 D P DP DP,讨论 a a a b b b ( 0 , r ) (0,r) (0,r) 的方案数
    满足 a a a & \& & b = 0 b = 0 b=0 只需要在每一位的与为 0 0 0
    最后容斥以下即可


    题解的方法太过可怕

核心:数位DP + 容斥

#include<bits/stdc++.h>
#define fi first 
#define se second 
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 2e5 + 5;
int T, a[40], b[40];
ll dp[40][2][2];ll dfs(int wz, int lim1, int lim2){if(wz == -1) return 1;ll &ret = dp[wz][lim1][lim2];if(ret != -1) return ret;int up1 = lim1 ? a[wz] : 1;int up2 = lim2 ? b[wz] : 1;ret = 0; for(int i=0; i<=up1; i++)for(int j=0; j<=up2; j++){if(i & j) continue;ret += dfs(wz-1, lim1&&(i==up1), lim2&&(j==up2));}return ret;
}ll cal(int l, int r){if(l<0 || r<0) return 0;memset(dp, -1, sizeof(dp));for(int i=30; ~i; i--){a[i] = l >> i & 1;b[i] = r >> i & 1;}return dfs(31, 1, 1);
}int main() {scanf("%d", &T);while(T--){int l, r;scanf("%d%d", &l, &r);printf("%lld\n", cal(r, r) - 2*cal(l-1, r) + cal(l-1, l-1));}
}
  相关解决方案