poj3252——數位dp(減去的藝術)

題目鏈接:https://vjudge.net/problem/POJ-3252

題目大意:求滿足區間[l,r]內滿足二進制0的個數大於1的個數的數的個數。

題解:設狀態dp[pos][sum]表示枚舉到第pos個位置,前面的所有數位的數的二進制0的個數減去1的個數。

因此sum可能小於0,且最小爲-32,因此我們可以離散化一下,把實際的-32看成0,實際的0看成32,

這樣只需要最後枚舉到-1時判斷一下最後是否大於等於32(其實就是大於等於0)

代碼實現:

#pragma GCC optimize(2)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#define PI atan(1.0) * 4
#define E 2.718281828
#define rp(i, s, t) for (register int i = (s); i <= (t); i++)
#define RP(i, t, s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define pii pair<int, int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a = 0, b = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            b = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        a = (a << 3) + (a << 1) + c - '0';
        c = getchar();
    }
    return a * b;
}
int a[64],num;
ll dp[36][64];
ll dfs(int pos,int sum,int lead,int limit){
    if(pos==-1) return sum>=32;
    if(!lead&&!limit&&dp[pos][sum]!=-1) return dp[pos][sum];
    int up=limit?a[pos]:1;
    ll ans=0;
    rp(i,0,up){
        if(lead&&i==0) ans+=dfs(pos-1,sum,1,limit&&i==a[pos]);
        else ans+=dfs(pos-1,sum+((i==0)?1:-1),lead&&i==0,limit&&i==a[pos]);
    }
    if(!limit&&!lead) return dp[pos][sum]=ans;
    return ans;
}
ll solve(ll x){
    num=0;
    while(x) a[num++]=x%2,x/=2;
    return dfs(num-1,32,1,1);
}
int main(){
    mst(dp,-1);
    ll l,r;
    while(~scanf("%lld%lld",&l,&r)){
        printf("%lld\n",solve(r)-solve(l-1));
    }
    return 0;
}

 

 

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