HDU - 6156 Palindrome Function(数位DP)

题目

题意:给你一个数据范围[L, R]问在这个数据范围内的x的f(x, k)之和为多少。f(x, k)如果x转换成k进制的时候是回文串,则f(x,k) = k,反之f(x, k) = 1。例如f(288, 17) ,288在17进制上是GG,为回文串,则f(288, 17) = 17;

刚开始做的时候,思路特别混乱,变量加的太多,导致代码乱七八糟,后来思路真的太乱了,就去看了一下大佬的代码,才明白,不要判断那么多条件,果然还是太久没做,还是要多练练啊。。A了之后仔细想想其实也没有很为难我。。可能脑子不太清醒,判断条件写的乱七八糟吧。。

思路:dp[位数][数字长度][进制数][是否为回文] ,因为进制数最小是2,2^30 > 1e9,所以我开了dp[40][40][40][2]。其它的看代码注释吧。

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

typedef long long ll;
ll dp[40][40][40][2];
int num[40];     //记录回文串pos位置的当前数字
int a[40];    //记录每一位数字限制

ll dfs(int pos,int len,int k,int sta,int limit){
    if(pos == -1)
        return sta?k:1;
    if(!limit && dp[pos][len][k][sta] != -1)
        return dp[pos][len][k][sta];
    int up = limit?a[pos]:k-1;        //这时候是k进制,所以如果没有限制最大为k-1,不要和10进制弄混了
    ll ans = 0;
    for(int i = 0; i <= up; i++){     //枚举每一位的数字
        num[pos] = i;                //记录pos位的数字为多少,后面判断回文
        if(i == 0 && len == pos)     //如果len == pos说明前面都是0, 如果i == 0,则len-1。
            ans += dfs(pos-1, len-1, k, sta, limit&&i==a[pos]);
        else if(sta && pos < (len + 1)/2)   //如果sta == 1说明前面的字母都还符合回文串或则还没枚举到一半的位置,pos 判断是否枚举到一半以后的位置
            ans += dfs(pos-1, len, k, i == num[len-pos], limit&&i==a[pos]);
        else    //要么sta == 0,后面的不管多少都不会是回文串,要么pos >= (len+1)/2还没到判断的时候,所以sta不变
            ans += dfs(pos-1, len, k, sta, limit&&i == a[pos]);
    }
    if(!limit)
        dp[pos][len][k][sta] = ans;
    return ans;
}


ll slove(int x,int l,int r){
    ll ans = 0, x0 = x;;
    for(int i = l; i <= r; i++){     //枚举每一进制
        int pos = 0;
        x = x0;         //这一步别忘了
        while(x){
            a[pos++] = x%i;    //这里是取余进制数,不是10,别弄混了
            x /= i;
        }
        ans += dfs(pos-1, pos-1, i, 1, 1);
    }
    return ans;
}

int main(){
    int t, L, R, l, r, Case = 1;;
    scanf("%d",&t);
    memset(dp, -1, sizeof(dp));
    while(t--){
        scanf("%d%d%d%d",&L,&R,&l,&r);
        printf("Case #%d: %lld\n",Case++,slove(R, l, r)- slove(L-1, l, r));    //L记得-1
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值