Milliard Vasya's Function(Ural_1353)
Vasya is the beginning mathematician. He decided to make an important contribution to the science and to become famous all over the world. But how can he do that if the most interesting facts such as Pythagor’s theorem are already proved? Correct! He is to think out something his own, original. So he thought out the Theory of Vasya’s Functions. Vasya’s Functions (VF) are rather simple: the value of the Nth VF in the point S is an amount of integers from 1 to N that have the sum of digits S. You seem to be great programmers, so Vasya gave you a task to find the milliard VF value (i.e. the VF with N = 109) because Vasya himself won’t cope with the task. Can you solve the problem?
Input
Integer S (1 ≤ S ≤ 81).
Output
The milliard VF value in the point S.
Sample
input
1
output
10
程式碼
一開始打表找規律,雖然能看出點什麼來但還是差那麼一點,直接用動規的思想來想(謝QAQ巨巨的指導), 假設我們當前要求的是100以內各位數之和和等於s的數有多少個,可以想到就是10以內各位數之和等於s的數的個數再加上10到100內的各位數之和等於s的個數。令dp[i][j]就代表10的j次方內各位數之和等於i的數的個數,那麼dp[i][j] = dp[i][j - 1] + (10的j-1次方到10的j次方內各位數之和等於i的數的個數)。那麼後邊這一部分怎麼求呢?我們可以把j位數拆成j-1位數再加一位,要想讓各位數之和等於i,那麼加的這一位數只能是1到9中的任意一個數(不能是0的原因不用說了吧),假設我們加的數是1,那麼我們剩下j-1位的和只能是i-1,也就是dp[i - 1][j - 1],如果加的數是2,那麼我們剩下的j-1位的和就是dp[i - 2][j - 1],以此類推,狀態轉移方程就出來了,dp[i][j] = dp[i][j - 1] + dp[i - k][j - 1] ( 1 <= k <= 9)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
long long dp[83][12];
memset(dp, 0, sizeof(dp));
for(int i = 0; i <= 9; i++)
{
dp[i][1] = 1;
dp[0][i] = 1; //這個初始化是因為s小於10的時候比如說s=2時,會有2000這樣的數,這在我們分的情況中沒有出現,
} //因此可以把這個用不到的s=0時的處值設成1,s從1到9都可以加到這個數,方便計算
for(int j = 2; j <= 9; j++)
{
for(int i = 1; i <= 81; i++)
{
dp[i][j] = dp[i][j - 1];
for(int k = 1; k <= 9 && k <= i; k++)
{
dp[i][j] += dp[i - k][j - 1];
}
}
}
dp[1][9]++; //1還多一種1000000000的情況
int n;
scanf("%d", &n);
printf("%lld\n", dp[n][9]);
return 0;
}