题意:定义函数f(n, k): 当n在k进制下为回文串时,f(n, k) = k; 否则 f(n, k) = 1;
给你一个区间 [L, R].对于区间的每一个数i, 计算 j 属于 l 到 r 进制的f(i,j) 的和。
分析:因为进制的区间很小,我们可以枚举每一个进制k,计算[L, R]在k进制下有多少回文数。然后结果就是区间长度减去回文串数(这些事函数值为1 的部分)加上回文串数乘k(函数值为k的部分)。思路很简单,求回文数可以用数位dp,但是比赛的时候没写数位dp,觉得乱搞就可以过。
我们找[0,n]在k进制下回文串数量的时候,可以先找到比n小的第一个回文串。因为回文串时对称的我们可以直接考虑一半。按回文串的奇偶分两种情况讨论。好像比数位dp快一些。
#include<stdio.h>
#include<algorithm>
#include<string>
#include<iostream>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#define mo 1000000007
#define mm %mo
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
ll primesize;
ll prime[N], phi[N], isP[N], miu[N];
ll a[N], len;
inline ll qucickM(ll a, ll b){
ll c = 1;
while(b){
if(b & 1) c = c * b mm;
b >>= 1;
a = a * a mm;
}
return c;
}
void getR(ll t, ll k, int de){
if(t < k){
a[++len] = t;
return;
}
getR(t / k, k, de + 1);
a[++len] = t % k;
}
ll solve(ll t, ll k){
if(t == 0) return 0;
len = 0;
getR(t, k, 1);
if(len % 2){
int mid = len / 2 + 1, le, re;
for(le = mid - 1, re = mid + 1; le > 0 && re <= len && a[le] == a[re]; re++, le--);
if(le >= 1 || re <= len) {
if(a[le] > a[re]){
int pos = 0;
for(pos = mid; pos >= 0 && a[pos] == 0; pos--);
a[pos] -= 1;
if(pos)for(int j = pos + 1; j <= mid; j++) a[j] = k - 1;
if(pos == 1 && a[pos] == 0){
len--;
for(int i = 1; i <= len; i++) a[i] = k - 1;
goto l1;
}
}
for(int i = 1, j = len; j >= i; i++, j--){
a[j] = a[i];
}
}
}else{
int mid = len / 2, le, re;
for(le = mid, re = mid + 1; le > 0 && re <= len && a[le] == a[re]; re++, le--);
if(le >= 1 || re <= len) {
if(a[le] > a[re]){
int pos = 0;
for(pos = mid; pos >= 0 && a[pos] == 0; pos--);
a[pos] -= 1;
if(pos)for(int j = pos + 1; j <= mid; j++) a[j] = k - 1;
if(pos == 1 && a[pos] == 0){
len--;
for(int i = 1; i <= len; i++) a[i] = k - 1;
goto l1;
}
}
for(int i = 1, j = len; j >= i; i++, j--){
a[j] = a[i];
}
}
}
l1:
if(len % 2 == 0){
ll p = 0, q = 1;
for(int i = 1; i <= len / 2; i++){
p = p * k + a[i];
q = q * k;
}
return p + q - 1;
}else{
ll p = 0, q = 1;
for(int i = 1; i <= len / 2; i++){
p = p * k + a[i];
q = q * k;
}
if(len == 1) return a[1];
return (p - 1) * (k) + a[len / 2 + 1] + 1 + (q - 1) + k - 1;
}
}
int main(){
int T;
//freopen("a.txt", "r", stdin);
//freopen("b2.txt", "w", stdout);
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
ll L, R, l, r, ans = 0;
scanf("%lld%lld%lld%lld", &L, &R, &l, &r);
for(ll i = l; i <= r; i++){
ll sl = solve(L - 1, i);
ll sr = solve(R, i);
ll tot = R - L + 1;
ans += tot - (sr - sl) + i * (sr - sl);
}
printf("Case #%d: %lld\n", kase, ans);
}
return 0;
}