T54351 袁绍的刁难
传送门
思路:
真的是一道送命题啊。
假定只有 5 个将领的时候,各个将领的武力值为:1、3、9、27、81。
首先,对于每个将领只有取与不取两种状态。而且,任意一个将领之前的所有将领的武力值全部加起来也不会超过这个将领的武力值。
假设第 n 个将领之前的全部都取了,武力总值为第 k 小。则第 k+1 小的武力值,就是只取第 n 个将领,前面的将领全都不取。
如果只取第 n 个将领的武力值为第 k1 小,第 n+1 个将领的武力值为第 k2 小,则中间的第 k1 + 1 ~ k2 -1 小,就是一定要取第 n 个将领,再从 1 ~ n-1 个将领中选出将领进行组合。
会发现,这样的选取就是二进制的 。
这时,就可以直接的将要求的 k 转换成二进制 。如果是二进制位是 0 就表示这个武将不取,如果二进制位是 1 就表示这个武将要取 。
直接统计答案就行了。
Code:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<cstdlib> #include<stack> #include<vector> #include<queue> #include<deque> #include<map> #include<set> using namespace std; #define lck_max(a,b) ((a)>(b)?(a):(b)) #define lck_min(a,b) ((a)<(b)?(a):(b)) const int maxn=55; typedef long long LL; LL T,k,top,ans,las,st[maxn]; inline LL read() { LL kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } inline void out(LL xs) { if(!xs) {putchar(48); return;} if(xs<0) putchar('-'),xs=-xs; int kr[57],ls=0; while(xs) kr[++ls]=xs%10,xs/=10; while(ls) putchar(kr[ls]+48),ls--; } inline LL work(LL u) { while(u) { st[++top]=u%2; u/=2; } } inline void clear() { las=1,top=0,ans=0; memset(st,0,sizeof(st)); } int main() { T=read(); while(T--) { k=read(); clear();work(k); for(LL i=1;i<=top;i++) ans+=st[i]*las,las*=3; out(ans); putchar('\n'); } return 0; }