hdu 6156 Palindrome Function

来源:互联网 发布:淘宝代理货源平台 编辑:程序博客网 时间:2024/06/05 13:35

题意

定义函数 f(n,k),当 nk 进制表示为回文数时,f(n,k)=k;否则 f(n,k)=1 。求 Ri=Lrj=lf(i,j) 。(1T105,1LR109,2lr36

题解

可以发现 l,r 的范围很小,直接枚举 j 代表 j 进制,对于 i 用数位dp统计即可。

比赛的时候竟然没做这一题。。。蠢死了 ┭┮﹏┭┮

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int B=40;int dig[B],tmp[B];ll dp[B][B][B];int base;ll dfs(int pos,int start,bool limit){    if (pos<0) return 1;    if (!limit&&dp[base][pos][start]!=-1) {        return dp[base][pos][start];    }    int last=limit?dig[pos]:base-1;    ll res=0;    for (int i=0;i<=last;i++) {        tmp[pos]=i;        if (pos==start&&i==0) {            res+=dfs(pos-1,start-1,limit&&(i==last));        } else if (pos<(start+1)/2) {            if (i==tmp[start-pos]) {                res+=dfs(pos-1,start,limit&&(i==last));            }        } else {            res+=dfs(pos-1,start,limit&&(i==last));        }    }    if (!limit) dp[base][pos][start]=res;    return res;}ll calc(int x){    int len=0;    while (x) {        dig[len++]=x%base;        x/=base;    }    return dfs(len-1,len-1,1);}int main(){    memset(dp,-1,sizeof(dp));    int T,cas=0;    scanf("%d",&T);    while (T--) {        int L,R,l,r;        scanf("%d%d%d%d",&L,&R,&l,&r);        ll ans=0;        for (base=l;base<=r;base++) {            ll cnt=calc(R)-calc(L-1);            ans+=cnt*base+(R-L+1-cnt);        }        printf("Case #%d: %lld\n",++cas,ans);    }    return 0;}