题目大意:
有一堆夜宵摆在小学生们一个人面前,第iii份夜宵美味值为3i−13^{i-1}3i−1,请问小学生们他应该怎么选才能使美味值为第k(1≤k≤231−1)k(1 \leq k \leq 2^{31}-1)k(1≤k≤231−1)大
解题思路:
比赛的时候:
我先打了个暴力
然后打表找规律
我用3x3^x3x划分每一行,也就是说:
第一行:111
第二行:3, 43,\ 43, 4
第三行:9, 10, 12, 139,\ 10,\ 12,\ 139, 10, 12, 13
然后我发现第iii行有2i−12^{i-1}2i−1个数,接着我们就能找出kkk在第几行第几个
又因为我是按照333的次幂分行,所以第iii行的开始就是3i−13^{i-1}3i−1
后来我第一反应是枚举
接着发现会TTT飞
然后我就尝试判断k所在位置的数分解为333的次幂的结果
于是我随机找了一行:
81, 82, 84, 85, 90, 91, 93, 94, 108, 109, 111, 112, 117, 118, 120, 12181,\ 82,\ 84,\ 85,\ 90,\ 91,\ 93,\ 94,\ 108,\ 109,\ 111,\ 112,\ 117,\ 118,\ 120,\ 12181, 82, 84, 85, 90, 91, 93, 94, 108, 109, 111, 112, 117, 118, 120, 121
303^030分布(0(0(0表示有,1,1,1表示没有))):
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,10, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 10,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1
我发现如果在第xxx个数中有303^030,则(x−1) mod 2+1>1(x-1)\ mod\ 2 + 1 > 1(x−1) mod 2+1>1
313^131
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,10, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 10,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1
接着发现如果在第xxx个数中有313^131,则(x−1) mod 4+1>2(x-1)\ mod\ 4 + 1 > 2(x−1) mod 4+1>2
接着往下推
323^232
0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,10, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 10,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1
333^333
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,10, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 10,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1
发现若(x−1) mod 2i+1+1>2i(x-1)\ mod\ 2^{i+1} + 1 > 2^{i}(x−1) mod 2i+1+1>2i(∀iϵ[0,32]\forall i\epsilon [0, 32]∀iϵ[0,32]表示iii次幂),则第kkk个数分解为333的次幂后,分解出来的式子中含有3i3^i3i
然后我们将其累加,记为sumsumsum
最后的第kkk个数就是sum+3x−1sum+3^{x-1}sum+3x−1(此时xxx表示第kkk个数在第xxx层)
请无视上面的找规律过程
将kkk转换为二进制数再把转换后的二进制数看做三进制数后转换为十进制
嗯,没错,这就是
正解
Accepted code:Accepted\ code:Accepted code:
#include<cstdio>
#include<algorithm>
using namespace std;
int lr, T, n = 0;
long long last;
long long p2[63], p3[33];
long long get_ans(int x, int lr) {
long long sum = 0;
for (int i = 0; i < 33; ++i)
sum += p3[i] * ((x-1) % p2[i+1] + 1 > p2[i] ? 1LL : 0LL);
return sum + p3[lr];
}
int main() {
/*freopen("recruitment.in", "r", stdin);
freopen("recruitment.out", "w", stdout);*/
p2[0] = p3[0] = 1;
for (int i = 1; i < 63; ++i) p2[i] = p2[i-1] << 1;
for (int i = 1; i < 33; ++i) p3[i] = p3[i-1] * 3;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
last = 0; lr = 0;
while (n - (last + p2[lr]) > 0)
last += p2[lr++];
printf("%lld\n", get_ans(n - last, lr));
}
//fclose(stdin);
//fclose(stdout);
return 0;
}