#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);
}
}
HDU6156 Palindrome Function(回文数)
最新推荐文章于 2020-08-17 19:04:32 发布