題意:定義函數 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;
}