HDU6156 Palindrome Function[数位DP]

Palindrome Function

  HDU - 6156






 

题意:

给T组数据,每组数据含有 L,R,l,r, 求出函数

其中f(i,j)表示


题解:

这很容易把思维转向知道R里面有多少个回文数,L-1(因为范围包括了L)里面有多少个回文数,减去差值然后乘上权值j,,再加上[L,R]之间不能构成回文数的个数,就可以得到答案了。

其中,十进制的回文数判断,在LightOJ1205出现过,如果没做过的,可以现去做做这题。

我们用同样的方法,只要多一维记录下当前进制。

那么最后我们可以得到dp[k][i][j][2] 第一维表示k进制下,第二维表示当前位置,第三维表示回文数的长度(从0开始,理解为起点也可以),第四维表示是否能构成回文串。

每次记录下当前枚举的数。

判断过程中,对前导0作处理,也就是说当当前位置与回文数长度一致时,而当前枚举为0,那么回文数长度跟着当前位置减一,然后再继续往下找。

当当前位置距离回文数的长度,超过了一半的时候,开始判断后面枚举的数是否与前面已经枚举了的数出现回文。

最后根据f(i,j)的值,对回文数的个数处理一下就好。


T_T 一开始我还傻傻的以为自己算错算错,其实只是算了回文数的个数。



#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int M=40;
ll dp[M][M][M][2];
int num[M],tmp[M];
ll dfs(int pos,int k,int cnt,bool state,bool limit)
{
    if (pos==-1)
        return state;
    if (!limit && dp[k][pos][cnt][state]!=-1)
        return dp[k][pos][cnt][state];
    int up=limit?num[pos]:k-1;
    ll res=0;
    for (int i=0 ; i<=up ; ++i)
    {
        tmp[pos]=i;
        if (pos==cnt && !i)
            res+=dfs(pos-1,k,cnt-1,state,limit && i==num[pos]);
        else if (state && pos<(cnt+1)/2)
            res+=dfs(pos-1,k,cnt,i==tmp[cnt-pos],limit && i==num[pos]);
        else
            res+=dfs(pos-1,k,cnt,state,limit && i==num[pos]);
    }
    if (!limit)
        dp[k][pos][cnt][state]=res;
    return res;
}
ll solve(int x,int k)
{
    int pos=0;
    while (x)
    {
        num[pos++]=x%k;
        x/=k;
    }
    ll ans=dfs(pos-1,k,pos-1,1,1);
    return ans;
}
int main()
{
    memset(dp,-1,sizeof(dp));
    int T;
    scanf("%d",&T);
    for (int test=1 ; test<=T ; ++test)
    {
        int L,R,l,r;
        scanf("%d%d%d%d",&L,&R,&l,&r);
        ll ans=0;
        for (int i=l ; i<=r ; ++i)
        {
            ll rn=solve(R,i);
            ll ln=solve(L-1,i);
            ans+=(rn-ln)*i;
            ans+=(R-rn-(L-1-ln));
        }
        printf("Case #%d: %lld\n",test,ans);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值