题目大意:题目在这里
给你一个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;
}
呼呼