CodeForces - 598A Tricky Sum (暑假集训测试一A)

题目大意题目在这里

  给你一个n,要你求出从1到n的数字和,其中如果数字是2的指数值,就取负数加在和里,最后输出加出来的和。

题目思路

  本来是很简单的,麻烦的就在题目中给的数据范围太大了——(1 ≤ n ≤ 10^9),而时间限制是1000ms,可以试一下单单从1到10^9循环一遍时间就超了。但其实可以发现,2^32就已经超过了10^9,所以我们可以考虑用递推把需要变为负号的和事先依次算出来,很快的。然后还记不记得从1加到n我们的公式……(反正我第一次没有想起来好蠢还试图一个一个加嘤),然后看n之前有几个是2的指数次,减去两倍的负号和就可以了。

跳的坑:

  最开始统计的是到2^27(鬼知道我是什么心态只统计到27,可是27次方明明也超过了10^9呀嘤嘤……)然后输入10,0000,0000时结果一直不对也是很无奈了,一直以为是算那个公式(n+1)*n/2时中间是不是溢出了,改了几次越改越错得离谱……(A题一直写不出来也是很崩溃了),后来灵机一动把27改的大了一点,就改到30就AC了……(难过。写了那么久还WA了一发)

题目代码

#include<iostream>
#include<cstdio>
#define maxn 42

using namespace std;
long long power[maxn],sum1[maxn];

int main(void)
{
    int t;
    int u;
    long long n;
    long long sum;
    power[0]=1;
    sum1[0]=-1;
    for(int i=1;i<=30;i++)
    {
        power[i]=power[i-1]*2;//
        sum1[i]=sum1[i-1]-power[i]; //计算从2^0加到2^i的和的负数
    }
    scanf("%d",&t);
    while(t--)
    {
        sum=0;
        scanf("%lld",&n);
        for(int i=0;i<=30;i++)
        {
            if(n<power[i])
            {
                u=i-1;
                break;
            }
            else if(n==power[i])
            {
                u=i;
                break;
            }
        }
        //printf("%d--\n",u);
        if(n%2==0)
            sum=(1+n)*(n/2)+sum1[u]+sum1[u];
        else
            sum=((n+1)/2)*n+sum1[u]+sum1[u];
        printf("%lld\n",sum);
    }
    return 0;
}

呼呼

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/81201702