数位dp(二进制01问题)

题意:给你一个区间,求区间有多少个满足条件的数。条件是:把该数转为二进制后,如果0的数量大于等于1的数量,则为满足条件的数量。

题解:数位dp【pos】【sta】表示第pos位,pos前面位数的0数量-1数量为sta的,且满足条件的数的数量。

因为在dfs过程中sta可能为负数(数组下标不能为负数),但又并不能却定该数最终是否符合条件,所以sta初始值为32就避免了负数。因为前导零会影响结果,所以要分类讨论。

//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include<time.h>
#include <vector>
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 20191117
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int a[40];
int dp[40][70];

int dfs(int pos , int sta , int lead , int limit)
{
    if(pos == -1) return sta >= 32;
    if(!limit && !lead && dp[pos][sta] != -1) return dp[pos][sta];
    int up = limit ? a[pos] : 1 ;
    int ans = 0 ;
    for(int i = 0 ; i <= up ; i++)
    {
        if(lead && i == 0) ans += dfs(pos-1 , sta , lead , limit && a[pos] == i);
        else ans += dfs(pos -1 , sta + (i == 0 ? 1 : -1) , false , limit && a[pos] == i);
    }
    if(!limit && !lead) dp[pos][sta] = ans ;
    return ans ;
}

int solve(int x)
{
    int pos = 0 ;
    while(x)
    {
        a[pos++] = x % 2 ;
        x /= 2 ;
    }

    return dfs(pos-1 , 32 , true , true);
}

int main()
{
    /*#ifdef ONLINE_JUDGE
    #else
        freopen("D:/c++/in.txt", "r", stdin);
        freopen("D:/c++/out.txt", "w", stdout);
    #endif*/
    int l , r ;
    memset(dp , -1 , sizeof(dp));
    scanf("%d%d" , &l , &r);
    printf("%d\n" , solve(r) - solve(l-1));





    return 0;
}

猜你喜欢

转载自www.cnblogs.com/nonames/p/12000308.html