【HDU6156】Palindrome Function(数位DP+回文串)

题意:

求在[L,R]之间的所有的回文串的个数,但是有一个附加条件就是在不同的进制下,题目要求即为:给定L,R, l,r

,    

 

分析:

这道题首先可以简化一下,问题简化为在K进制下,[L, R]中的回文串的数目,因为进制只有36个,而且是不是一个数字是不是回文串是一个数字的自身的属性,因此可以直接在DP数组上不断处理,然后利用保留的信息加速计算,也就是先枚举进制在K进制下用数位DP求个数,设个数为X,那么在K进制下的结果为

这样就可以求出结果了,而且速度还可以。

 

这里有一个数位DP求回文串个数的参考资料:http://blog.csdn.net/u013200703/article/details/47662409

 

AC代码:

 

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;
int bits[50];
ll dp[50][50][50];
int base;
ll dfs(int len,int l,int r,bool flag,bool ok)
{
    if(r > l) return !flag || (flag && ok);
    if(!flag && ~dp[len][l][base])  return dp[len][l][base];
    int end = flag ? bits[l] : base - 1;
    ll res = 0;
    for(int i=0;i<=end;i++)
    {
        if(l == len && i == 0) continue;
        bool g = ok;
        if(ok) g = bits[r] >= i;
        else g = bits[r] > i;
        res += dfs(len,l-1,r+1,flag&&(i==end),g);
    }
    return flag ? res : dp[len][l][base] = res;
}
ll solve(ll x)
{
    if(x < 0) return 0;
    if(x == 0) return 1;
    ll tt = x;
    int cnt = 0;
    while(tt >0 )
    {
        bits[++cnt] = tt % base;
        tt /= base;
    }
    ll ret = 1;
    for(int i=cnt;i>=1;i--)
        ret += dfs(i,i,1,i==cnt,true);
    return ret;
}
int main()
{
    int CASE;
    scanf("%d", &CASE);
    memset(dp, -1, sizeof(dp));//一个数是不是回文串是一个数自身的性质,
    //不受数据范围的影响,所以只要初始化一次dp数组,大大减少了时间
    for(int cas = 1; cas <= CASE; ++cas)
    {
        ll l, r;
        int bl, br;
        scanf("%I64d%I64d%d%d",&l,&r, &bl, &br);
        ll ans = 0LL;
        for(base = bl; base <= br; ++base)
        {
            ll cnt = solve(r) - solve(l - 1);
            ans = ans + cnt * base + (r - l + 1 - cnt);
        }
        printf("Case #%d: %I64d\n", cas, ans);
    }
    return 0;
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值