數位dp就是要統計一個區間[l, r]內滿足給定條件數的個數
控制上界,往下枚舉
Description
A number X have n digits(A1A2A3......An)
F(x) = A1*2n-1 + A2*2n-1 .....+An-1*21 + An *20
Now, give you two number A, B
You need to calculate how many number's F(x) is no more than F(A) between 0 to B
Input
T(0 < T<= 10000) T is TestCase
A, B (0 <= A, B <= 1000000000)
Output
Answer
Sample Input
11 1
Sample Output
Case #1: 2
#include <cstdio>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define PI acos(-1)
#define inf 0x3f3f3f3f
#define EPS 1e-6
#define mem(a, b) memset(a, b, sizeof(a))
#define ll long long
#define mian main
#define N 10010
int a[20];//存放分開的數位
int dp[20][N];//dp[i][j]表示i位值<=j 的總數
ll f(ll x)//計算F(x)
{
int ans = 0;
int cs = 1;
while(x)
{
int tmp = x%10;
x /= 10;
ans += tmp * cs;
cs *= 2;
}
return ans;
}
int dfs(int pos, int sum, bool lim/*數位上界變量*/)
{
/*lim的作用,比如界限爲521,搜到百位的時候枚舉0~5,枚舉4時可以有499枚舉到5的時候599>521了所以用lim*/
if(sum < 0)return 0;
if(pos == -1 && sum >= 0) return 1;//到了數位的最後一位並且這一位合法
if(!lim && dp[pos][sum] != -1)return dp[pos][sum];
int up = lim ? a[pos] : 9;//判斷枚舉上界(達到上界是a[pos]其他時候是9)
int ans = 0;
for(int i = 0; i <= up; i++)//枚舉這一位可能的數字
{
ans += dfs(pos - 1, sum - i * (1<<pos), lim && i == a[pos]);//遞歸,狀態轉移
}
if(!lim) dp[pos][sum] = ans;
return ans;
}
ll solve(int x, int y)//分出數位來
{
int pos = 0;
while(x)
{
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos - 1, y, 1);//從最高位開始枚舉
}
int main()
{
int t;
int no = 0;
ll a, b;
cin>>t;
mem(dp, -1);
while(t--)
{
//mem(a, 0);
no++;
cin>>a>>b;
//cout<<f(a)<<endl;
int tmp = f(a);
cout<<"Case #"<<no<<':'<<' '<<solve(b, tmp)<<endl;
}
return 0;
}