數位DP
講一下具體思路,自己是看了kuangbin的板子來做的
DP的關鍵在於如何去尋找轉移方程,本道題用到了一種相減的思路
A,B分別代表題目描述的變量
DP[pos][sum] pos 不用多說就是數位, sum這裏不是指一個數的和,這裏的sum指的是距離湊滿F(A)還需要多少數這樣子轉移方程就可以記憶化了,爲什麼呢?當第一步的時候指的是DP[pos][F(A)],但是繼續往下dfs,因爲每一步都要減去一個數,這個時候sum,更新成了一個新的數字,這個時候我們求得就是距離湊滿新的sum還需要多少的數,這樣就跟F(A)相當於脫離了,每一個求出來的DP[][]是可以作用於所有的數的如果還不明白可以自己在程序上做幾個測試點幫助自己理解,只要記住DP[pos][sum]求的是在pos位,距離湊滿sum的數有多少就行
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int case_ = 0;
int dp[20][6000];
int p[20];
int dfs(int pos, int sum, bool limit){
if(sum < 0) return 0;
if(pos == -1 && sum >= 0) return 1;
if(!limit && dp[pos][sum] != -1) return dp[pos][sum];
int up = limit? p[pos]: 9;
int ans = 0;
for(int i = 0; i <= up; i++){
ans += dfs(pos-1, sum - i*(1<<pos), limit && i==p[pos]);
}
if(!limit) dp[pos][sum] = ans;
return ans;
}
int F(int x){
int sum = 0;
int len = 0;
while(x){
sum += (x%10)*(1<<len);
len++;
x /= 10;
}
return sum;
}
int solve(int y, int x){
int len = 0;
while(x){
p[len++] = x%10;
x /= 10;
}
return dfs(len-1, F(y), true);
}
int main()
{
int TestCase;
memset(dp, -1, sizeof(dp));
scanf("%d", &TestCase);
int A, B;
while(TestCase--){
scanf("%d%d", &A, &B);
printf("Case #%d: %d\n", ++case_, solve(A, B));
}
return 0;
}