LG9154
很显然地,除了 \(3^0\) 只能选一次外,每个 \(3\) 的幂最多可以用两次。于是我们可以类比二进制拆分的思路,依次枚举 \(3\) 的幂,每次找到小于当前数的最大的幂并减去,统计次数,发现非 \(0\) 次幂出现次数大于 \(2\) 或 \(0\) 次幂大于 \(1\) 时则输出 \(0\),否则运用乘法原理计数。
本人在赛时发现了一个规律:对于任意的 \(a \equiv0 \pmod3\),都有 \(ans_a = ans_{a+1}\)。因此可以直接转换后计算。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int unsigned long long
using namespace std;
int inv[38];
int pd[38];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
signed main()
{
int T,ans,k;
int n;
inv[0] = 1;
for( int i = 1 ; i <= 37 ; i ++ )
inv[i] = inv[i - 1] * 3;
cin >> T;
while( T -- )
{
k = 0;
memset( pd , 0 , sizeof(pd) );
ans = 0;
n = read();
if( n % 3 == 0 ) n ++,k = 1;
while( n > 0 )
{
int i;
for( i = 0 ; i <= 37 ; i ++ )
{
if( inv[i] > n )
break;
}
if( pd[i - 1] == 2 )
{
ans = 0;
break;
}
pd[i - 1] ++ ;
n -= inv[i - 1];
ans ++;
}
if( ans == 0 ||( pd[0] > 1 && !k)) cout << 0 << endl;
else
{
ans = 1;
for( int i = 1 ; i <= 37 ; i ++ )
if( pd[i] == 1 )
ans = ans * 2;
cout << ans << endl;
}
}
return 0;
}
还是菜。