HDU6156 Palindrome Function(回文数)

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
/*
k进制下的回文数

如果n在k进制下是回文数f(n,k)=k,否则f(n,k)=1
n和k的变化范围为L<=n<=R,l<=k<=r,计算f(n,k)的累加和

对于一个数,比如k进制下,从高位到地位表示为,456123
k[]=321654、x=654、y=123、len=6
由于x>y,那么最大回文数应该为455554
否则,最大的回文数应该是456654,对于后面的个数需要-1个
在len=6时,最小的回文数为100001,也就是len=6时回文数的个数为(456-100+1)-1个
*/
long long dp[40][50];//在i进制下j位数的回文数个数
//xx为允许最大的数,上限,p为进制,也是当前进制下每个回文数的权值
long long slove(long long xx,long long p)
{
    long long ans=0;//0-xx 在p进制下回文数个数
    if(xx==0)
        return 0;
    int k[500];
    int len=0;//p进制表示时,数的位数
    long long q=xx;
    while(q)//在p进制下分解
    {
        k[len++]=q%p;
        q/=p;
    }
    if(len==1)
        return xx*p;//回文的个数*每个回文数权值
        long long x=0,y=0,z=0;
    if(len%2==0)//位数为偶数
    {
        //当前这个数分为前后两个部分
        for(int i=len/2;i<len;i++)//计算前一半数倒置的大小
            x=x*p+k[i];
        for(int i=len/2-1;i>=0;i--)//计算后一半数的大小
            y=y*p+k[i];
        int flay=0;
        if(x>y)//前面一个数的倒置比后一个数大
            flay=-1;
        z=k[len-1]-1;//z为k进制时,xx这个数回文数的个数,少了1个
        for(int i=len-2;i>=len/2;i--)
            z=z*p+k[i];
        z+=flay;//最大的那个回文数不可能的情况
        ans=z+1;//+1个
        for(int i=1;i<len;i++)
            ans+=dp[p][i];
    }
    else
    {
        for(int i=len/2+1;i<len;i++)
            x=x*p+k[i];
        for(int i=len/2-1;i>=0;i--)
            y=y*p+k[i];
        int flay=0;
        if(x>y)
            flay=-1;
        z=k[len-1]-1;
        for(int i=len-2;i>=len/2;i--)
            z=z*p+k[i];
        z+=flay;
        ans=z+1;
        for(int i=1;i<len;i++)
            ans+=dp[p][i];
    }
    return ans*p+xx-ans;//回文个数*每个回文权值+(数总的个数-回文个数)*1(不是回文权值)
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i=2;i<=36;i++)//i进制
    {
        dp[i][1]=i-1;
        dp[i][2]=i-1;
        for(int j=4;j<=32;j+=2)//在i进制下,数的位数为j
        {
            dp[i][j]=dp[i][j-2]*i;
            dp[i][j-1]=dp[i][j];
            if(dp[i][j]>=1000000000)
                break;
        }
    }
    int cas=0;
    while(t--)
    {
        long long L,R,l,r;
        long long ans=0;
        scanf("%lld%lld%lld%lld",&L,&R,&l,&r);
        for(int i=l;i<=r;i++)//枚举进制
        {
            ans+=slove(R,i);
            ans-=slove(L-1,i);
        }
        printf("Case #%d: %lld\n",++cas,ans);

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值