数位DP

参考于大佬的Blog

记录两个模板题

(CF276D Little Girl and Maximum XOR)

A little girl loves problems on bitwise operations very much. Here's one of them.
You are given two integers \(l\) and \(r\) . Let's consider the values of \(a ^ b\) for all pairs of integers \(a\) and \(b\) \((l \le a \le b \le r)\) . Your task is to find the maximum value among all considered ones.
Expression \(x ^ y\) means applying bitwise excluding or operation to integers \(x\) and \(y\) . The given operation exists in all modern programming languages, for example, in languages C++ and Java it is represented as "^", in Pascal — as «xor».
Input
The single line contains space-separated integers \(l\) and \(r\) ( \(1 \le l \le r \le 10^{18}\) ).
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
Output
In a single line print a single integer — the maximum value of \(a ^ b\) for all pairs of integers \(a\) , \(b\) ( \(l \le a \le b \le r\) ).

此题不是计数问题,因此不可以用前缀和的思想直接用f(r) - f(l - 1)的方式去求。我们可以对上下界(\(l,r\)) 分别设置一个limit标记去解决。同时,因为要枚举两个数字,要分别为两个数字设上下标记,即一共要设\(4\)个标记。

#include <bits/stdc++.h>
#define TEST int T; read(T); while(T --) 

//#define int long long 
#define endl '\n' 

using namespace std;
typedef long long LL;

template < typename T >
inline void read(T &x)
{
    x = 0; bool f = 0; char ch = getchar();
    while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
    while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
    x = f ? -x : x;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
{ read(x),read(args...); }
template <typename T> void read(vector<T> &A) { for(T &x: A) read(x);};


LL L[64], R[64], dp[64][2][2][2][2];
LL cnt, cnt1, cnt2;

inline void solve() {
    LL a, b;
    read(a, b);
    // 题目大意 0-a 0-b   之间选择两个数字,求出 XOR 最大值
    /** 
     * 利用数位DP
     * 每次求出当前位可能的最大值 
     * 递归求出即可
     * 较为模板化
     */
    function <LL(int, bool, bool, bool, bool)> dfs = [&] (int pos, bool lit1, bool rit1, bool lit2, bool rit2) {
        LL ans = 0;
        if(pos == cnt) return 0LL;
        auto &d = dp[pos][lit1][rit1][lit2][rit2];
        if(d != -1) 
            return d;

        for(LL u = (lit1 ? L[pos] : 0); u <= (rit1 ? R[pos] : 1); u ++ )
            for(LL v = (lit2 ? L[pos] : 0); v <= (rit2 ? R[pos] : 1); v ++ ) 
                ans = max(ans, ((u ^ v) << (cnt - pos - 1)) + dfs(pos + 1, lit1 && u == L[pos], rit1 && u == R[pos], lit2 && v == L[pos], rit2 && v == R[pos])) ;
        return ans;
    };

    while(a) L[cnt1 ++] = a & 1, a >>= 1;
    while(b) R[cnt2 ++] = b & 1, b >>= 1;
    memset(dp, -1, sizeof dp);
    cnt = max(cnt1, cnt2);
    reverse(L, L + cnt);
    reverse(R, R + cnt);
    
    printf("%lld", dfs(0, true, true, true, true));
}
signed main() 
{
    solve();
    return 0;
}

2020年ICPC区域赛上海站的C题也是二进制数位DP。

\(\sum_{i=0}^{X} \sum_{j=[i==0]}^{Y}\) [\(i\) & \(j\)\(==\)\(9\)] \(\left \lfloor {\log_{2}{i + j } + 1} \right \rfloor\) \(modulo\) \(10^9 + 7\)

对于给定的 \(X,Y\)求出上式的值
首先分析一下这个式子
如果有值,则\(i&j\)一定为\(0\),这就代表了\((i + j)\)是不涉及进位的,那么\(\left \lfloor {\log_{2}{i + j } + 1} \right \rfloor\)代表的值其实就是 \(\max(i, j)\)的最高位在哪一位.
因此我们就可以进行 数位DP 对每一位进行 记忆化搜索即可 qwq

#include <bits/stdc++.h>
#define fi first    
#define se second    
#define pb push_back
#define mk make_pair
#define leng(a) (int)a.size()
#define lowbit(x) (x&-x)
#define fix(a) fixed << setprecision(a) 
#define debug(x) cout<<#x" ----> "<<x<<endl
#define rep(i, b, s) for(int i = (b); i <= (s); ++i)
#define pre(i, b, s) for(int i = (b); i >= (s); --i)
#define TEST int T; read(T); while(T --) 

//#define int long long 
#define endl '\n' 
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
#define all(v) (v).begin(),(v).end()

using namespace std;
 
typedef unsigned long long ULL;
typedef pair<int, int> PII ;
typedef pair<int, PII> PIII ;// {value, {value, value}}
typedef pair<double, double> PDD ;
typedef long long LL;
const int INF = INT_MAX;
const LL INFF = INT64_MAX;
const int MOD = 1e9 + 7;
const double eps = 1e-10;
const double pi = acos(-1.0);
   
LL gcd(LL a, LL b) {return b ? gcd(b, a%b) : a;}
inline LL ksm(LL a, LL b) {if (b == 0) return 1; LL ns = ksm(a, b >> 1); ns = ns * ns % MOD; if (b & 1) ns = ns * a % MOD; return ns;}
inline LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
inline void out(bool flag);
inline bool valid(char c) { return 33<=c&&c<=126; }
template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
template <typename T> inline T mod(T &x) {return x % MOD;}
template < typename T >
inline void read(T &x)
{
    x = 0; bool f = 0; char ch = getchar();
    while(!isdigit(ch)){f ^= !(ch ^ 45);ch=getchar();}
    while(isdigit(ch)) x= (x<<1)+(x<<3)+(ch&15),ch=getchar();
    x = f ? -x : x;
}
template<typename T,typename ...Args>void read(T &x, Args &...args)
{ read(x),read(args...); }
template <typename T> void read(vector<T> &A) { for(T &x: A) read(x);};
inline void reads(char *s) {
    int l=0;char c;
    while(!valid(s[0]=getchar()));
    while(valid(s[++l]=getchar()));
}


// __builtin_popcount(x) 返回x中1的个数
// __lg(x) 返回x的二进制下的位数(去除前导零实现,特判0)
//map<key,value>; key 可以是PII

//再用unordered_map 是sb
const int N = 64;
LL dp[N][2][2][2];
LL L[N], R[N];
int cnt, cnt1, cnt2;


inline void solve() {
    LL a, b; read(a, b);
    memset(dp, -1, sizeof dp);
    memset(L, 0, sizeof L);
    memset(R, 0, sizeof R);
    cnt1 = 0, cnt2 = 0;
    while(a) L[cnt1 ++] = a & 1, a >>= 1;
    while(b) R[cnt2 ++] = b & 1, b >>= 1;
    cnt = max(cnt1, cnt2);
    reverse(L, L + cnt);
    reverse(R, R + cnt);

    function <LL(int, bool, bool, bool) > dfs = [&] (int pos, bool lim1, bool lim2, bool lead) {
        LL ans = 0, res = 0;
        if(pos == cnt) return 1LL;
        auto &d = dp[pos][lim1][lim2][lead];
        if(d != -1) return d;
        for(int u = 0; u <= (lim1 ? L[pos] : 1); ++ u)
            for(int v = 0; v <= (lim2 ? R[pos] : 1); ++ v) {
                if(u & v) continue;
                //111100
                //012345
                //6-
                if(lead && (u || v)) res = cnt - pos;
                else res = 1;
                ans = (ans + dfs(pos + 1, lim1 && u == L[pos], lim2 && v == R[pos], lead && !u && !v) * res % MOD) % MOD;
            }
        d = ans;
        return ans;
    };
    printf("%lld\n", (dfs(0, true, true, true) - 1 + MOD) % MOD);


}
 
signed main() 
{
    TEST
    solve();
 
    return 0;
}
 
 
inline void out(bool flag) {
    if(flag) puts("YES");
    else puts("NO");
}
posted @ 2021-11-18 23:55  ccz9729  阅读(40)  评论(0编辑  收藏  举报