1. 程式人生 > 其它 >洛谷P2602 [ZJOI2010]數字計數

洛谷P2602 [ZJOI2010]數字計數

洛谷P2602 [ZJOI2010]數字計數

原題連結

數位dp

這也是一道比較基礎的數位dp題。

有一點需要注意,需要加上前導0的判斷,否則在統計0的個數時會多餘統計很多數

直接看程式碼吧(有註釋)

不會真的有人寫數位dp不用深搜吧,不會吧,不會吧

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long

using namespace std;

ll l, r, len;
ll num[15], dp[13][13][2][2];	//dp[len][sum][flag][lim]

ll dfs(ll len, ll now, ll sum, ll flag, ll lim){	//len:當前處理到x的第幾位,now:當前在查詢數字幾的個數,sum:當前數字出現了幾次,flag:前導0判斷(1:是 0:否),lim:上界判斷(1:有 0:無)
	if(!len) return sum;	//處理完了,返回sum
	if(dp[len][sum][flag][lim] != -1) return dp[len][sum][flag][lim];	//記憶化
	ll res = lim ? num[len] : 9;
	ll ans = 0;
	for(ll i = 0; i <= res; i++)
		ans += dfs(len - 1, now, sum + (!(flag && (!i)) && (i == now)), flag && (!i), lim && (i == res));		//這個sum傳遞好好看看,要判斷是否是前導0
	return dp[len][sum][flag][lim] = ans;
}

ll solve(ll x, ll now){
	len = 0;
	while(x){
		num[++len] = x % 10;	//這裡是倒著存x的每一位的
		x /= 10;
	}
	memset(dp, -1, sizeof(dp));	//dp陣列還是-1
	return dfs(len, now, 0, 1, 1);
}

signed main(){
	scanf("%lld%lld", &l, &r);
	for(ll i = 0; i <= 9; i++)
		printf("%lld ",solve(r, i) - solve(l - 1, i));	//字首和思想統計答案
	printf("\n");
	return 0;
}

完結撒花~