URAL - 1057 Amount of Degrees 數位DP

在這裏插入圖片描述
思路

  • 對於一個數 n, 我們求他的 0 - n 的滿足要求的方案數, 對於區間[l, r] = sum[r] - sum[l - 1]
  • 我們先預處理組合數, 存下對應的值
  • 我們這時取出n的每一位的值, 我們去判斷一下這位的樹, 如果這一位不是0, 我們直接加上這一位是0的情況, 就是這以爲不選1, 前面選了last個1, 後面再選k - last個1, 就是f[i], k - last], 對於這一位大於1這種情況, 後面就可以隨便選, 這一位選上1, 這樣最後組成的數一定是小於n的, 對於這位是1的情況, 我們就只有選0或者選1, 0已經前面加上了, 所以就只需要處理1這種情況,但是由於1這種情況, 後面還需要討論, 不能亂取, 所以這不符合組合數, 我們直接last++就行

代碼

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N  = 35;

int f[N][N];
int x, y, k, b;

void init()
{
	for(int i = 0; i <= 34; i++)
	{
		f[i][0] = 1;
		for(int j = 1; j <= i; j++)
			f[i][j] = f[i - 1][j - 1] + f[i - 1][j];	
	}
}

int dfs(int x)
{
    if(!x) return 0;
	vector<int> num;
	while(x) num.push_back(x % b), x /= b;
	int ans = 0;
	int last = 0;
	for(int i = num.size() - 1; i >= 0; i--)
	{
		int n = num[i];
		if(n)
		{
			ans += f[i][k - last];
			if(n > 1) // 這位就隨便取 
			{
				if(k - last - 1 >= 0)
					ans += f[i][k - last - 1];
				break;
			}
			else
			{
				last++;
				if(last > k)
					break;
			}
		}
		if(!i && k == last)//特判一下最後的一種情況
			ans++;
	}
	return ans;
}

int main()
{
	cin >> x >> y >> k >> b;
	init();
	int ans = dfs(y) - dfs(x - 1);
	cout << ans << endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章