T1:果果趣

首先观察每 15 个连续正整数组成序列中不包含特殊词汇对应的原始数字有 8 个:1、2、4、7、8、11、13、14。所以可以将 n 除以 8 取商 d 和余 r,然后根据 dr 计算结果。

如果 r0,则结果为 d×15 加上数组 a[r] 中对应元素
如果 r=0,则结果为 d×151
这样就可以在 O(1) 时间内找出第 n 个非特殊词汇对应的原始数字。

代码实现
#include <bits/stdc++.h>
using namespace std;
int a[] = {14, 1, 2, 4, 7, 8, 11, 13};
int main() {
int n;
cin >> n;
int d = n/8, r = n%8;
int ans = d*15;
if (r != 0) ans += a[r];
else ans--;
cout << ans << '\n';
return 0;
}

T2:阿兹特克

求前 k 小的在 10 进制和 p 进制下都是回文的数之和。

参考难度:黄题

分析

70分做法:

从小到大枚举数,然后分别按照十进制和 p 进制做数位拆分。对拆分之后得到的两个数组,分别判断是否为回文。

然而,这一做法需要从小到大枚举数字,对于本题而言,最坏情况为 k=30p=7 时,第 30 个满足条件的数为 64454545446,从 1 开始枚举显然超时,期望得分 70 分。

100分做法:

实际上,除了个位数的回文数,其他回文数都可以通过翻转得到,即,先确定左半部分的数位,右半部分的数位通过翻转得到。

这一做法只需枚举左半部分的数位,对于上文提到的最坏情况,仅需枚举到 64454。但是我们需要确保所有满足条件的数是从小到大枚举到的,所以我们可以按照如下方式枚举:

  • 先枚举 19 中的数,相当于 10 进制下的个位回文数,判断是否为 p 进制回文数
  • 从小到大循环枚举左半部分的位数 bit
    • 先枚举偶数位的回文数,,其为 2bit
    • 再枚举奇数位的回文数,其为 2bit+1

这个方法枚举的数字最多 105 个,期望得分 100 分。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int p, k;
bool isPalindrome(ll x) {
string s;
do {
s += x%p+'0';
x /= p;
} while (x);
string t = s;
reverse(t.begin(), t.end());
return s == t;
}
ll f(ll x) {
int res = 0;
do {
res = res*10 + x%10;
x /= 10;
} while (x);
return res;
}
int main() {
cin >> p >> k;
ll ans = 0;
int cnt = 0;
for (int i = 1; i <= 9 and cnt < k; ++i) {
if (isPalindrome(i)) {
ans += i;
++cnt;
}
}
vector<int> pow10(7, 1);
rep(i, 6) pow10[i+1] = pow10[i]*10;
for (int l = 1, r = 10, bit = 1; cnt < k; l *= 10, r *= 10, ++bit) {
// 从小到大枚举左半边,取值范围 [l, r),为 bit 位,依次得到从小到大的回文数
for (ll i = l; i < r and cnt < k; ++i) {
ll rev = f(i);
ll num = i*pow10[bit] + rev;
if (isPalindrome(num)) {
ans += num;
++cnt;
}
}
// 构造 2bit+1 位的奇数位回文数,必然大于所有的 2bit 位偶数位回文数,
// 且小于之后的 2(bit+1) 位的偶数位回文
for (ll i = l; i < r and cnt < k; ++i) {
// 中间位也需要从小到大枚举
for (int mid = 0; mid <= 9 and cnt < k; ++mid) {
ll rev = f(i);
ll num = i*pow10[bit+1] + mid*pow10[bit] + rev;
if (isPalindrome(num)) {
ans += num;
++cnt;
}
}
}
}
cout << ans << '\n';
return 0;
}