HDU - 6156 数位dp求k进制下回文串的个数

用数位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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值