数学太差自闭了。

题意:

给一个数n,问你大于等于n的数中,可以拆分成3的幂之和的最小的数,其中每个幂最多出现一次

题解:

先将n分解成三进制,然后观察,当某位出现2的时候,我们需要从大于这位的幂开始寻找一位出现0次的幂,将其改成1,同时将小于这个幂出现次数被改成1的幂的出现次数全部改成0

如:  ,3^0这个幂出现次数为2,那么从该幂开始寻找一个幂出现次数为0,那么就是3^3将其换成1,同时3^0,3^1,3^2出现次数全部换成0,即答案为

证明:

考虑极端情况:

那么对于任意的三位三进制数,如果每一位都不小于1,同时如果某位为2,那么不可能大于等于

因此得证.

 

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
ll n, q, g;
int three[70];

void trans(){
	memset(three, 0, sizeof three);
	g = 0;
	ll t = n;
	while(t){
		three[++g] = t % 3;
		t /= 3;
	}
}

ll process(){
	 trans();
	 
	 ll now = 0;
	 for(int i = 1; i <= g; i++){
	 	if(three[i] == 2){
	 		for(int j = i + 1; ; j++)
	 			if(three[j] == 0){
	 				if(now < j) now = j;
	 				break;
	 			}
	 	}
	 }
	 g = max(g, now);
	 
	 if(!now) return n;
	 else {
	 	for(int i = 1; i < now; i++)
	 		three[i] = 0;
	 	three[now] = 1;
	 	
	 	ll ans = 0;
	 	for(int i = g; i >= 1; i--)
	 		ans = (ans * 3 + three[i]);
	 	
	 	return ans;
	 } 
}

int main()
{
	scanf("%I64d", &q);
	
	while(q--){
		scanf("%I64d", &n);
		
		ll ans = process();
		
		printf("%I64d\n", ans);
	}
	
	return 0;
}