HDU 6156 Palindrome Function(数位DP)

本文介绍了一个利用数位动态规划(DP)解决特定范围内回文数计数问题的方法。具体地,给定两个整数范围[L, R]及进制范围[l, r],文章详细阐述了如何通过数位DP算法高效计算出所有可能的回文数数量。该算法的核心在于定义了一个四维的状态转移方程,并通过递归函数实现了状态的遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

定义函数f(n,k),如果nk进制下是回文数则f(n,k)=k,否则f(n,k)=1,给出L,R,l,r,求i=LRj=lrf(i,j)

Input

第一行输入一整数T表示用例组数,每组用例输入四个整数L,R,l,r

(1T105,1LR109,2lr36)

Output

对于每组用例,输出答案

Sample Input

3
1 1 2 36
1 982180 10 10
496690841 524639270 5 20

Sample Output

Case #1: 665
Case #2: 1000000
Case #3: 447525746

Solution

进制范围较小,直接枚举,问题变成求1~N中有多少数字在d进制下为回文数,数位DP,以dp[len][pos][pre][sta]表示当前数字长度为len,当前在第pos位,上一位数字是pre,回文状态是stasta=1表示回文,sta=0表示不回文)的数字个数,如果在放前半部分直接放即可,放后半部分时候判断与对称位置数字是否相同来改变回文状态

Code

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int T,Case=1,L,R,l,r,a[37],b[37]; 
ll dp[37][37][37][2];
ll dfs(int len,int pos,int d,int sta,int fp)
{
    if(!pos)
    {
        if(sta)return d;
        return 1;
    }
    if(!fp&&~dp[len][pos][d][sta])return dp[len][pos][d][sta];
    ll ans=0;
    int fpmax=fp?a[pos]:d-1;
    for(int i=0;i<=fpmax;i++)
    {
        b[pos]=i;
        if(len==pos&&i==0)ans+=dfs(len-1,pos-1,d,sta,fp&&i==fpmax);
        else if(sta&&pos<=len/2)ans+=dfs(len,pos-1,d,sta&&i==b[len+1-pos],fp&&i==fpmax);
        else ans+=dfs(len,pos-1,d,sta,fp&&i==fpmax); 
    }
    if(!fp)dp[len][pos][d][sta]=ans;
    return ans;
}
ll Solve(int n,int d)
{
    int len=0;
    while(n)a[++len]=n%d,n/=d;
    return dfs(len,len,d,1,1);
}
int main()
{
    memset(dp,-1,sizeof(dp));
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&L,&R,&l,&r);
        ll ans=0;
        for(int i=l;i<=r;i++)ans+=Solve(R,i)-Solve(L-1,i);
        printf("Case #%d: %I64d\n",Case++,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值