前n项和
看似好像很简单… 但是我不会 不过我搞懂了 了吧
题目如下:
求和公式
-
你可以累加 1+2+3+…+n-1+n
暴力求解前n项和 简单粗暴 但看数据规模就知道撑死能过60% -
Sn=n(a1+an)/2
在这道题里呢 这公式可以变换为 (n+n*n)/2 -
Sn=n*a1+n(n-1)d/2
在这道题里 可把公式变换为 n+n(n-1)/2 再进一步变换为 n * ( n + 1) / 2
其实上边那个公式也可以变换成这个形式
基本思路
知道公式了 我们就要想一下 怎么过那超过long long的范围
观察公式n * ( n + 1) / 2
是由n和n+1相乘再除2
如果n的位数很大呢 显然不能直接相乘算出答案
这时可以用到二进制
你没有看错
以样例100为例
答案 ans=(100*101)/ 2
101的二进制表示 0110 0101即
2
6
2^6
26+
2
5
2^5
25+
2
2
2^2
22+
2
0
2^0
20
ans=[100 * (
2
6
2^6
26+
2
5
2^5
25+
2
2
2^2
22+
2
0
2^0
20 ) ] / 2
等等 数据很大的时候可是要取模的 乘积除2可就又危险了 直接除会爆
这时候需要一个数等于mod的一半 和结果的乘积相乘 p=(1e9 +7) / 2 =500000004
然后这个式子就可以列成 ans=[100 * (
2
6
2^6
26+
2
5
2^5
25+
2
2
2^2
22+
2
0
2^0
20 ) ] * p % mod
涉及到了一些位运算的知识
& 这个是取二进制最后一位
一般可以用它判断奇偶 比如a是一个正整数 那么 a&1=0(就是偶数) a&1=1(就是奇数)
但是这里 只是用来判断一下 这个二进制位是否存在 存在就加到答案里
>> 右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,这样判断完一位丢一位 然后判断下一位
AC代码
按照以上思路 代码如下
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9 + 7; //宏定义mod数
const ll p = 500000004; //p 为 mod的一半
ll n, ans;
void nsum(ll x,ll y)
{
while(y>0){
if(y & 1) //判断该位是否存在
ans = (ans + x) % mod;
x = (2 * x) % mod; //x乘2
y = y >> 1; //将最后一位舍弃
}
return;
}
int main()
{
cin >> n;
nsum(n, n + 1);
ans = (ans * p) % mod;
cout << ans;
return 0;
}