题目链接:HDU - 6156
数位dp即可,每次转移的时候记录每个字符串的长度,以及当前选了的位数。
如果选了未超过一半,那么都可以选,否则只能选之前选的对称位的值。
注意处理前导零。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=90;
int dp[N][N][N],a[N],ts,b[N]; long long res;
int dfs(int pos,int len,int k,int zero,int lim){
if(!pos) return 1;
if(!zero&&!lim&&dp[pos][len][k]!=-1) return dp[pos][len][k];
int up=lim?a[pos]:k-1,res=0;
for(int i=0;i<=up;i++){
b[pos]=i;
if(zero&&!i) res+=dfs(pos-1,len-1,k,1,lim&&i==up);
else if(pos>len/2) res+=dfs(pos-1,len,k,0,lim&&i==up);
else if(i==b[len-pos+1]) res+=dfs(pos-1,len,k,0,lim&&i==up);
}
if(!lim&&!zero) dp[pos][len][k]=res;
return res;
}
inline int calc(int x,int k){
int pos=0;
while(x) a[++pos]=x%k,x/=k;
return dfs(pos,pos,k,1,1);
}
inline void solve(){
int l,r,L,R; res=0;
scanf("%lld %lld %lld %lld",&L,&R,&l,&r);
for(int i=l;i<=r;i++){
int tmp=calc(R,i)-calc(L-1,i);
res+=tmp*i+(R-L+1-tmp);
}
printf("Case #%lld: %lld\n",++ts,res);
}
signed main(){
memset(dp,-1,sizeof dp);
int T; cin>>T; while(T--) solve();
return 0;
}