前n项和 大数取余

前n项和

看似好像很简单… 但是我不会 不过我搞懂了 了吧
题目如下:

前n项和 大数取余_第1张图片

求和公式

  1. 你可以累加 1+2+3+…+n-1+n
    暴力求解前n项和 简单粗暴 但看数据规模就知道撑死能过60%

  2. Sn=n(a1+an)/2
    在这道题里呢 这公式可以变换为 (n+n*n)/2

  3. Sn=n*a1+n(n-1)d/2
    在这道题里 可把公式变换为 n+n(n-1)/2 再进一步变换为 n * ( n + 1) / 2
    其实上边那个公式也可以变换成这个形式

基本思路
知道公式了 我们就要想一下 怎么过那超过long long的范围
观察公式n * ( n + 1) / 2
是由nn+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 
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;  
}

你可能感兴趣的:(前n项和 大数取余)