题意:定义函数 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;
}