Palindrome Function(hdu - 6156)
题目链接:Palindrome Function(hdu - 6156)
题意:
f (n,k) = k(在k进制下为回文串)否则为1 (2 <= k <= 36)
找出区间为(L, R)的数i , 在区间为(l, r) 的进制j, 函数f(i, j)的和 (L, R <=1e9)
已知:
回文串:由前半部分可知后半部分,构造回文串只需遍历1e5 (10进制条件下)(其余进制需要扩大范围,在代码注释里有提)
计算:遍历进制,求出给定区间内包含 构造回文串数组 的个数,再求和
思路来源:
code:
#include <algorithm>
#include <iostream>
#include <math.h>
#include <map>
#include <vector>
#include <string.h>
using namespace std;
typedef long long ll;
const ll mxx = 1e9 + 100;
int num[100];
vector<int> x[40];
void init()
{
int cnt = 0, cut = 0;
for (int xx = 1; xx <= 200100; xx++) {
for (int j = 2; j <= 36; j++) {
int t = xx, p = 0;
while (t) {
num[p++] = t % j;
t /= j;
}
ll a = xx, b = xx * j + num[0]; // b重复最后一位数字
// a构造出的回文串比b少一位
/*
关于xx设为1e5的范围,为什么不能AC:
a相当于10进制条件下构造出的回文串后半部分比前半部分少一位
而a在10进制条件下构造出的回文串正好可以满足1e9
但在若其余进制下去掉的数字是一个大于10的数,说明去多了,再换回10进制也就不能满足1e9
*/
for (int ii = 1; ii < p; ii++)
a = a * j + num[ii], b = b * j + num[ii];
if (a < mxx) x[j].push_back(a), cnt++;
if (b < mxx) x[j].push_back(b), cnt++;
}
}
for (int i = 2; i <= 36; i++) sort(x[i].begin(), x[i].end());
}
int main()
{
init();
int cas;
scanf("%d", &cas);
for (int Cas = 1; Cas <= cas; Cas++) {
int L, R, l, r;
ll sum = 0;
scanf("%d%d%d%d", &L, &R, &l, &r);
for (int i = l; i <= r; i++) {
ll len = upper_bound(x[i].begin(), x[i].end(), R) - lower_bound(x[i].begin(), x[i].end(), L);
sum += i * len + (R - L + 1 - len);
}
cout << "Case #" << Cas << ": " << sum << endl;
}
return 0;
}