UVa 11121 - Base -2 负进制的转化和推广

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2062


题目大意就是给你一个-1000,000,000到1000,000,000的数转化成-2进制。

看到-2就想到了2进制,原先想两位两位地考虑,然后看成2进制的,接下来求一下方程的正数解就行了,然后将那些数全都转化成0和1,后来又发现。。每项之间差了4倍,顿时就不行了。接着想着是不是能将 (-2)^k 和 2^k 联系起来,那问题就简单了。

后来看到了一个式子,顿时有了点灵感 : (4)^3 = (-4)^4 + (4 - 1) * (-4)^3

想了想后总结出来了一个结论

①当k是奇数的时候, 2^k = (-2)^(k+1) + (-2)^k;

②当k是偶数的时候, 2^k = (-2)^k;

推导的过程中也有遇到一些问题,一直想把偶数和奇数的情况联系在一起,但是感觉做不到,而且可能会出现负数,出现负数就不好处理了。

有了以上的结论,差不多就可以开始动手了。但是突然想到,负数的话,算出来的东西就会出问题了,想了想,负数和整数应该有类似的结论,经过尝试后推倒出这样的结论。

①当k是奇数的时候, -2^k = (-2)^k;

②当k是偶数的时候, -2^k = (-2)^(k + 1) + (-2)^(k + 1);

接下来就开始写代码了,但是测试了一下,一些数转化后出现了让人觉得很囧的大于1的数字,突然想到还要经行进位处理。想了想挺容易推导的,但是注意最好不要出现负数的情况,不然就不好处理了。

2 * (-2)^k = (-2)^(k + 1) + (-2)^(k + 2);

于是进位的操作就ok了

但程序到这里还是有bug的,试了一下1000,000,000,结果发现后面的结果还是很正常,前面多出了个4,顿时觉得很纳闷,然后认真地调试了下,发现出现了一个4和2的循环,高位的系数是2,低位的系数是4,突然反应过来,完全是可以抵消掉的,但是没有抵消就出现了4和2的循环。

ans[k+1] = 2ans[k];

每次进位前先进行抵消操作,然后开始进位,接下来程序终于没了bug了,顺利AC了。


其实这个还是可以推广的,按照刚才的公式,我们假设现在是(-b)进制,有以下的结论

n为正数

①当k为奇数的时候,b^k = (-b)^(k + 1) + (b - 1) * (-b)^k

②当k为偶数的时候,b^k = (-b)^k;

n为负数

①当k为奇数的时候,- b^k = (-b)^k;

②当k为偶数的时候,- b^k = (-b)^(k + 1) + (b - 1) * (-b) ^ k;

进位:

①当k为偶数的时候,b * (-b)^k = (-b)^(k + 1);

②当k为奇数的时候,b * (-b)^k = - b^(k + 1) = - (-b)^(k + 1) = - b^(k + 1) = (-b)^(k + 2) + (b - 1) * (-b)^(k + 1);

抵消

ans[k+1] = b * ans[k];

 

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAXN = 64 + 5;

int n, flag;
int ans[MAXN];

int main()
{
    int tCase;

    while(scanf("%d", &tCase) != EOF)
        for(int T = 1; T <= tCase; ++ T)
        {
            flag = 1;
            scanf("%d", &n);
            memset(ans, 0, sizeof(ans));

            if(n < 0)
            {
                flag = 0;
                n = ~n + 1;
            }

            //转化
            for(int i = 0; i < 31; ++ i)
                if(n & (1 << i))
                {
                    ++ans[i];

                    if((i & 1) == flag)
                        ++ans[i + 1];
                }

            //进位
            for(int i = 0; i < MAXN - 1; ++ i)
            {
                //抵消
                if(ans[i] >= ((ans[i + 1] >> 1) << 1))
                {
                    ans[i] -= ((ans[i + 1] >> 1) << 1);
                    ans[i + 1] -= (ans[i + 1] >> 1);
                }

                while(ans[i] > 1)
                {
                    ++ans[i + 1];
                    ++ans[i + 2];
                    ans[i] -= 2;
                }
            }

            printf("Case #%d: ", T);

            for(int i = MAXN - 1; i > 0; -- i)
                if(ans[i] != 0)
                {
                    for(int j = i; j > 0; --j)
                        putchar(ans[j] + '0');

                    break;
                }

            putchar(ans[0] + '0');
            putchar('\n');
        }

    return 0;
}
View Code

 

 

 


 

转载于:https://www.cnblogs.com/tank39/p/3911404.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值