题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6156
题意:算十进制下数字在[L,R]内用[l,r]进制表述下的数字贡献。
贡献有两种:回文数,贡献是进制k;不是回文数,贡献是1。
由于进制只有36个,枚举进制分别做统计回文数的数位dp即可,贡献按要求。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int maxn = 1010; 6 const int maxm = 55; 7 const LL mod = 1e9+7; 8 int digit[maxn], revert[maxn]; 9 LL L, R, l, r; 10 LL dp[maxm][maxm][maxn][2]; 11 12 LL dfs(int k, int s, int l, bool ok, bool flag) { 13 if(l < 0) { 14 if(ok) return k; 15 return 1; 16 } 17 if(!flag && ~dp[k][s][l][ok]) return dp[k][s][l][ok]; 18 int pos = flag ? digit[l] : k - 1; 19 LL ret = 0; 20 for(int i = 0; i <= pos; i++) { 21 revert[l] = i; 22 if(i == 0 && s == l) { 23 ret += dfs(k, s-1, l-1, ok, flag&&(i==pos)); 24 } 25 else if(ok && l < (s + 1) / 2) { 26 ret += dfs(k, s, l-1, i==revert[s-l], flag&&(i==pos)); 27 } 28 else { 29 ret += dfs(k, s, l-1, ok, flag&&(i==pos)); 30 } 31 } 32 if(!flag) dp[k][s][l][ok] = ret; 33 return ret; 34 } 35 36 LL f(LL n, LL k) { 37 if(n == 0) return k; 38 int pos = 0; 39 while(n) { 40 digit[pos++] = n % k; 41 n /= k; 42 } 43 return dfs(k, pos-1, pos-1, 1, 1); 44 } 45 46 47 signed main() { 48 // freopen("in", "r", stdin); 49 int T, _ = 1; 50 scanf("%d", &T); 51 memset(dp, -1, sizeof(dp)); 52 while(T--) { 53 scanf("%lld%lld%lld%lld",&L,&R,&l,&r); 54 LL ret = 0; 55 for(int i = l; i <= r; i++) { 56 ret += f(R, i) - f(L-1, i); 57 } 58 printf("Case #%d: %lld ", _++, ret); 59 } 60 return 0; 61 }