題目大意:求滿足區間[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; }