G - 不容易系列之二

由于徐老汉没钱,收费员就将他的羊拿走一半,看到老汉泪水涟涟,犹豫了一下,又还给老汉一只。巧合的是,后面每过一个收费站,都是拿走当时羊的一半,然后退还一只,等到老汉到达市场,就只剩下3只羊了。

你,当代有良知的青年,能帮忙算一下老汉最初有多少只羊吗?
Input
输入数据第一行是一个整数N,下面由N行组成,每行包含一个整数a(0<a<=30),表示收费站的数量。
Output
对于每个测试实例,请输出最初的羊的数量,每个测试实例的输出占一行。
Sample Input
2
1
2
Sample Output
4
6

#include <stdio.h>
int main()
{
    int i,a,sheep,N;
    scanf("%d",&N);
    while(N--)
    {
        scanf("%d",&a);
        sheep=3;
        for(i=0;i<a;i++)
            sheep=(sheep-1)*2;
        printf("%d\n",sheep);
    }
    return 0;
}

附一个大佬的解答来于百度知道
SekaiAmber
这是一个OJ问题吧~~
首先,咱要说的是OJ问题基本上不是编程题,而是数学题或者短码编程题~
这个问题其实是个数学题,可以发现当羊数量a从检查站数量1-30递增过程中,是有规律的,关系为:
a(n) = (a(n-1) - 1) * 2.
求其通项公式为:
a(n) = 2^(n-1) * a(1) - 2^(n-1) + 2.
其中a(1) = 3,则a(n) = 2^n + 2.
所以计算时不需要用循环,比如输入2的时候,则羊的数量即为2^2 + 2 = 6。
而计算2^n不需要用pow函数,直接用位操作<<即可。
所以程序就很容易出来啦~
#include <stdio.h>
int main()
{
long n;
scanf("%ld", &n);
if(n > 0 && n <= 30)
{
n = (1 << n) + 2;
printf("%ld", n);
}
return 0;
}
要注意其中代表羊数量的那个值n,因为至少要大于2^30 + 2,所以类型必须为long,long的范围上限是2^31 - 1。
但是这不是最省资源和时间的算法。我们来改造这个程序,首先这里我们申请了一个变量n,这个n用来输入和输出,这是一个资源,我们把它去掉。
main函数隐藏的两个参数正好拿来用,并且if判断语句可以被三元运算符代替,且在某些编译器下效率更高,至少是一样的。
另外关于include,其实直接去掉即可,不用写,我们这里只用到了scanf和printf,大多数编译器直接认定自己的标准输入输出,为了优化代码,所以即使不用stdio,仍然可以被识别。
所以程序变成了这样~
int main(int argc, char** argv)
{
scanf("%d", &argc);
((30 - argc) >= 0)?printf("%ld", (long)(1 << argc) + 2):0;
}
OK,这可能不是最简单的方法,不过应该足以应付了~
PS,执行更加迅速的方法是hack,如果不考虑源码的长度,那么可以这么做,因为a的范围已经限制在了1到30内,那么用手算出a是1到30的所有结果,然后初始化一个29个元素的答案数组,使用switch判断a的值,直接输出答案。
PS2,更加快的是不管他输入什么,你都输出你推测的答案,然后不停的去试,人品爆发,刚好那次测试通过,这个解刚好是他输入的值的解,这时候程序运行是出奇的快。这是最恶心的hack,像POJ里面很多题目只有一个解,基本上大家都是不管三七二十一,先用手算出来,直接输出答案的。。。
PS3,如果楼主懂汇编,可以直接在.c文件中写汇编代码,直接输出1内存左移输入值+2的值即可。虽然不知道为什么这么设计,但是C文件中可以内嵌一定的汇编代码,并且可以被编译。
PS4,做OJ题就不能走常规路哦~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值