用数位DP求k进制的回文串个数,当时没想到数位DP过程中怎么记录回文的状态,还以为要把回文状态都记在dp数组里面。后来补了一下,发现只要开一个数组来存回文状态,因为dfs深搜过程中,过程之间互不影响,并且回文状态可以在那个数组上重复写入读出。
/*************************************************************************
> Author: MentalOmega
> Mail: 965194745@qq.com
> Created Time: 2017年8月20日
> function:数位dp
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
long long int dp[40][40][40];
int dig[40];
int getdig(int x,int base)
{
int pos=0;
while(x)
{
pos++;
dig[pos]=x%base;
x/=base;
}
return pos;
}
int num[40];//用于记录回文串中的字(关键
long long int dfs(int pos,int len,int limit,int base)//pos表示的是处理到第pos位(从高到低),len表示的是回文串长度,limit表示的是这一位有没有限制,base是进制
{
if(pos < 1)
return len!=0;//不能全是0
if(!limit && dp[pos][len][base] != -1)
return dp[pos][len][base];
int end = limit ? dig[pos] : base-1;
long long int ret = 0;
for(int i = 0; i <= end; i ++)
{
if(pos<=len/2&&i==num[pos])//这种情况是搜索到了回文串的后半部分
ret+=dfs(pos-1,len,limit && (i == end),base);
else if(len==0&&i)//选这一位做回文串的首位,那么长度就为pos那么长了
{
num[1]=i;
ret+=dfs(pos-1,pos,limit && (i == end),base);
}
else if(len&&pos>(len)/2)//这种情况是回文串的前半部分
{
num[len-pos+1]=i;
ret+=dfs(pos-1,len,limit && (i == end),base);
}
else if(len==0&&i==0)//这种是前导零来的
{
ret+=dfs(pos-1,0,limit && (i == end),base);
}
}
if(!limit)//没有限制的dp值可以记下
dp[pos][len][base]= ret;
return ret;
}
long long solve(int r,int base)
{
int pos=getdig(r,base);
return dfs(pos,0,1,base);
}
int main()
{
if (fopen("in.txt", "r") != NULL)
{
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
}
memset(dp,-1,sizeof dp);
memset(num,-1,sizeof num);
int t;
cin>>t;
int icase=0;
while(t--)
{
printf("Case #%d: ",++icase);
int l,r,L,R;
scanf("%d%d%d%d",&l,&r,&L,&R);
long long ans=0;
for(int i=L;i<=R;i++)
{
long long ret = solve(r,i)-solve(l-1,i);
ans+=ret*i+r-l+1-ret;
}
printf("%lld\n",ans);
}
return 0;
}