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) <<'\n';
        else cout<<cal(r,r)<<'\n';
    }
    return 0;
}

 

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