hdu6156(數位dp)

題意:定義函數 f(n, k) 如果數n在k進制下是迴文數則f(n, k) = k,否則f(n, k) = 1,求n在L,R區間內k在l,r區間內的函數和

問題轉化爲求L,R區間內k在l,r區間內的迴文數的個數

對數位dp理解還是不夠深刻,比賽的時候想到數位dp沒敢開,賽後補題還是寫不出來,不會設狀態,看了網上博客定了3個狀態,dp[i][j][k]表示在i進制下,長度爲j,枚舉到第k位時,迴文串的個數, 其實數位dp的狀態是要表示同一類型的數,在這題裏的同一類型就是長度相同,進制相同,且同爲迴文串,主要還是狀態太難想了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

ll dp[100][100][50];
int num[100];
int nums[100];

ll dfs(int tot, int pos, int k, int lead, int limit)
{
	if (pos < 1) return 1;
	if (!limit && dp[k][tot][pos] != -1) return dp[k][tot][pos];
	int up = limit ? num[pos] : k-1;
	
	ll sum = 0;
	for (int i = 0; i <= up; i++)
	{
		nums[pos] = i;
		if (lead && i == 0) sum += dfs(tot-1, pos-1, k, lead, limit && i == up);
		else if (pos > tot / 2) sum += dfs(tot, pos-1, k, lead && i == 0, limit && i == up);//數的前一半可以取任意數字 
		else if (i == nums[tot-pos+1]) sum += dfs(tot, pos-1, k, lead && i == 0, limit && i == up);//數的後一半必須滿足迴文 
	}
	if (!limit) dp[k][tot][pos] = sum;
	return sum;
}

ll solve(int x, int k)
{
	int len = 0;
	while (x > 0)
	{
		num[++len] = x % k;
		x/= k;
	}
	return dfs(len, len, k, 1, 1);
}

int main()
{
	memset(dp, -1, sizeof(dp));
	int T, kase = 0;
	scanf("%d",&T);
	while (T--)
	{
		ll L, R, l, r;
		scanf("%lld%lld%lld%lld",&L,&R,&l,&r);
		ll sum = 0;
		for (int i = l; i <= r; i++)
		{
			ll ans = solve(R,i) - solve(L-1,i);
			sum += ans * i;
			sum += (R - L + 1 - ans);
		}
		printf("Case #%d: %lld\n",++kase,sum);
	}
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章