• CF 1245F Daniel and Spring Cleaning 数位dp


    题意:给你一个二元组(l,r),问在[l,r]内有多少组二元组(a,b)满足a+b==a^b。(1,2)和(2,1)算两组。

    思路:

    1. 很容易想到当且仅当两数每一位同为1才会出问题,也就是说异或是没有进位的。所以a+b==a^b的条件是a&b==1。

    2. cal(a,b)函数为[0,a]与[0,b]内符合条件的二元组数。那么求[l,r]区间内的二元组数等价于cal(b,b)-2*cal(a-1,b)+cal(a-1,a-1)。

    3. 剩下的就是数位dp了。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;++i)
    #define for1(i,n) for(int i=1;i<=n;++i)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int inf = 2e9+5;
    const ll INf = 8e18;
    
    int len1,len2;
    ll dp[35][2][2];
    int a[35],b[35];
    
    ll dfs(int pos,int lim1,int lim2){
        if(pos<0) return 1;
        if(dp[pos][lim1][lim2]!=-1) return dp[pos][lim1][lim2];
        int x = lim1?a[pos] : 1;
        int y = lim2?b[pos] : 1;
        ll ans = 0;
        forn(i,x+1){
            forn(j,y+1) if((i&j)==0) ans += dfs(pos-1,lim1?(i==a[pos]):0,lim2?(j==b[pos]):0);
        }
        dp[pos][lim1][lim2] = ans;
        return ans;
    }
    
    ll cal(int x,int y){
        memset(dp,-1,sizeof(dp));
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        forn(i,32){
            int z = 1<<i;
            if(z&x) a[i] = 1;
            if(z&y) b[i] = 1;
        }
        return dfs(31,1,1);
    }
    
    int main(){
        IO;cout.precision(10);cout<<fixed;
        int t;cin>>t;while(t--){
            int l,r;cin>>l>>r;
            if(l)cout << cal(r,r)-2*cal(l-1,r)+cal(l-1,l-1) <<'
    ';
            else cout<<cal(r,r)<<'
    ';
        }
        return 0;
    }
  • 相关阅读:
    单例 与 static
    ActiveMQ 核心概念
    Jconsole
    死锁
    document write & close
    java.nio.Buffer
    Java 线程控制(输出奇偶数)
    exist & in
    命运
    Super Jumping! Jumping! Jumping!
  • 原文地址:https://www.cnblogs.com/AlexPanda/p/12520279.html
Copyright © 2020-2023  润新知