HDU 3209 Scales(模拟三进制运算)

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.
 

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.
 

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;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值