Hdu 3709 Balanced Number

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

記憶化 ,用的數位dp的模式感覺 ,數位dp也是菜開始學的 感覺很難看了一些博客 最終艱難的把它a了,寫個題解來鞏固一下把儘量寫得詳細點。

網上很多博客都說直接枚舉支點 其實對這個不是很熟,下面就用我的話來表述一下這個題吧。

首先是暴力dfs,對於指定長度的一個數,小於它的數有多少是平橫數,根據自己理解到的數位dp的東西,根據指定長度,那麼對於長度達不到的數前面補0,這樣就避免了位數的關係 而且這樣也可以保證每一位數都能枚舉到,那麼這個題 我們枚舉那個數位是平衡點 假設是第i位是平衡點 那麼只需要重左加到右每次加的時候乘上位置差就可以了。

然後對於dp記憶 dp[i][j][sum]  表示剩餘長度爲i的時候 平衡點爲就的時候 兩邊邊差爲sum的時候有多少種平衡情況 注意havemax標記 因爲如果前一位不是最大值得時候那麼當前這一爲可以隨便取0~9 否則就只能取到當前位的最大值。注意dp記錄的也只能是沒有最大值得情況 因爲能對於每一種情況 如果沒有最大值 那麼枚舉的後續都是一樣的。ok上代碼

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;
#define LL long long
LL dp[20][20][2050];
int dig[20];
LL dfs(int len,int pos,int sum,bool haveMax)
{
	if(len<0)
	return sum==0?1:0;
	if(!haveMax && dp[len][pos][sum]!=-1)
	return dp[len][pos][sum];
	int maxNum = haveMax?dig[len]:9;
	LL ans = 0;
	for(int i = 0;i<=maxNum;i++)
	{
		ans+=dfs(len-1,pos,sum+(len-pos)*i,haveMax&&i==maxNum);
	}
	if(!haveMax)
	{
		dp[len][pos][sum] = ans;
	}
	return ans;
}
LL solve(LL n)
{
	int len = 0;
	while(n)
	{
		dig[len++] = n%10;
		n/=10;
	}
	LL ans = 0;
	for(int i = 0;i<len;i++)
	{
		ans+=dfs(len-1,i,0,true);
		//printf("%lld\n",ans);
	}
	return ans-(len-1);
}
int main()
{
	int t;
	memset(dp,-1,sizeof(dp));
	cin >> t;
	while(t--)
	{
		LL l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
	}
	return 0;
}


發佈了36 篇原創文章 · 獲贊 1 · 訪問量 7738
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章