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

时间:2022-12-16 11:37:53

题意:

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

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


分析:

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

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


这里有一个数位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;
}