1. 程式人生 > >51Nod1043 幸運號碼(動歸數位dp)

51Nod1043 幸運號碼(動歸數位dp)

我們用dp[i][j]表示的是前i位的數字和為j,j最大為9*i  ,前i位每位都是9的時候。   這樣假如我們求得了dp[n][1]一直到dp[n][9*n]的數字,那麼最終結果就是dp[n][1] * dp[n][1]  +   ... + dp[n][9*n] * dp[n][9*n]  .  但是這裡還有一個問題就是,dp[i][j] 表示的是前i位的數字和為j,但是我們知道前面的那個 i位 是 不能有前置0的,所以還有處理一下。

求結果的時候就是sum(有前置0的結果)*(不含前置0的結果)。沒有前置0的結果是 dp[i][j] - dp[i-1][j] ,  因為每次都是在前面加數字,所以要是i位和i-1位的和一樣,就是前置0的數字了。


接下來就是怎麼求解dp[i][j] 了, dp[i][j]+= dp[i-1][j-k]  ;  (j>=k,k=0,1,2...9)  .很好理解 。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int Mod=1e9+7;
long long dp[1005][9045];//前i個數的和為j 
int main()
{
	int i,j,k;
	memset(dp,0,sizeof(dp));
	for(i=0;i<=9;i++) 
		dp[1][i]=1;
	for(i=2;i<=1000;i++)
		for(j=0;j<=i*9;j++)
			for(k=0;k<=9;k++)
				if(j>=k)
					dp[i][j]=(dp[i][j]+dp[i-1][j-k])%Mod;
	int n;
	long long sum=0;
	cin>>n;
	for(i=1;i<=9*n;i++)
		sum=(sum+(dp[n][i]-dp[n-1][i])*dp[n][i])%Mod;		
	cout<<sum<<endl;
	return 0;
}