Problem Description
Give you a scale, a goods weigts m kilograms. And then give you some stones weighting 1, 3, 9, 27, ..., 3^k. Of course, the number of different weights' is only ONE.
Now put the goods on the left of scale. And then you should put some stones on two sides of scale to make the scale balanced.
Now put the goods on the left of scale. And then you should put some stones on two sides of scale to make the scale balanced.
Input
An integer m, stands for the weights of the goods (0 ≤ m ≤ 100 000 000)
Output
You should output two lines.
In the first line, the first integer N1 is the number of stones putting on the left of scale, and then N1 integers follow(in the ascend order), indicating the weight of stones putting on the left, seperated by one space. In the second line, please use the same way as the first line's to output the N2, which is the number of stones putting on the right side. Then following N2 integers, which are in ascending order, indicate the stones' weight putting on the right side.
In the first line, the first integer N1 is the number of stones putting on the left of scale, and then N1 integers follow(in the ascend order), indicating the weight of stones putting on the left, seperated by one space. In the second line, please use the same way as the first line's to output the N2, which is the number of stones putting on the right side. Then following N2 integers, which are in ascending order, indicate the stones' weight putting on the right side.
Sample Input
42 30
Sample Output
3 3 9 27 1 81 0 2 3 27
据说多校的题考智商。。。
题意:
给质量m放在天平左边,你拥有3^k(k∈(0,∞))的砝码,每种只有1个,砝码可以放在天平左右两边
要求找到使天平平衡的方案并输出具体做法
分析:
第一眼想dfs暴搜,后来一想,搜到哪里结束呢?而且也想不到好的剪枝方法,就算不WA也是TLE的
然后尝试DP或者找数学规律什么的,都没想出来。。。
听题解的时候差点抽自己,鶸在想DP的时候想过三进制进行状态压缩。。。却与三进制运算擦肩而过。。。
其实对进制熟的人很快可以想到,利用3^k这个规律
三进制数转成十进制数的公式里面不都是3^k吗。。。。
首先,天平的右边必然是所有三进制为0或1的数,因为每种砝码只能用0或1次(出现2的话某个砝码用了2次)
所以只需要先将天平左边的m转成三进制数,然后模拟三进制数对其进行加法(相当于执行放3的k次方的砝码的操作)
加到所有三进制位没有2为止,这样右边天平也可以用3的k次方的和表示
=-=鶸的表达能力。。。。说的不清不楚。。。。
不过如果想到三进制的话,不看题解自己也可以做。。。。。
code :
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int N = 33;//3^33 = 5*10^15
ll p3[N+5];//p3[i]记录3的i次方
void init()
{
p3[0] = 1;
for (int i = 1;i <= N;++i)
{
p3[i] = p3[i-1]*(ll)3;
}
}
int num[111];//保存三进制数的每一位
int up;//最高位的位置
void turn(int n,int k)//十进制数转k进制数
{
up = 0;
while (n) //结果逆序,num[0]是个位
{
num[up++] = n%k;
n /= k;
}
}
void toup(int pos)//模拟三进制运算
{
num[pos] += 1;
for (int i = pos;i < up;++i)//num逆序存的三进制数,所以这里进位正序来
{
if (num[i]>2) //进位
{
num[i] = 0;
num[i+1]++;
if (i == up-1) up++;//补高位
}
}
}
int main()
{
init();
int m;
while (~scanf("%d",&m))
{
mem(num,0);
turn(m,3);//转3进制数
int sl = 0,sr = 0;//左右两边要加的砝码数
bool add[N+5];mem(add,0);
for (int i = 0;i < up;++i)
{
if (num[i]==2)//不能重复
{
sl++;
toup(i);//模拟三进制加一
add[i] = 1;
}
}
if (sl == 0) puts("0");
else
{
printf("%d",sl);
for (int i = 0;i < up;++i) if (add[i]) printf(" %lld",p3[i]);
puts("");
}
for (int i = 0;i < up;++i) if (num[i] == 1) ++sr;
printf("%d",sr);
for (int i = 0;i < up;++i) if (num[i] == 1) printf(" %lld",p3[i]);
puts("");
}
return 0;
}