51nod-1225-余数求和(分块)

F(n) = (n % 1) + (n % 2) + (n % 3) + ...... (n % n)。其中%表示Mod,也就是余数。 
例如F(6) = 6 % 1 + 6 % 2 + 6 % 3 + 6 % 4 + 6 % 5 + 6 % 6 = 0 + 0 + 0 + 2 + 1 + 0 = 3。
给出n,计算F(n), 由于结果很大,输出Mod 1000000007的结果即可。
Input
输入1个数N(2 <= N <= 10^12)。
Output
输出F(n) Mod 1000000007的结果。
Input示例
6
Output示例
3



我们知道余数m= n-n/i*i;

显然sigma(i)n/i,n/i的值在一定区间内是不变的

于是根据n/i做公比,分块搞搞等比数列求和就好啦~,复杂度O(sqrt(n))。




//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define LL long long
#define bug cout<<"bug\n"
using namespace std;
const int MAXN = 1e7+7;
const int MAXM = 1e9+7;
const long long MOD = 1e9+7;
// m= n-n/i*i;
long long quick_pow(long long a,long long n)
{
    long long ans=1;
    while(n)
    {
        if(n&1)ans=ans*a%MOD,ans%=MOD;
        a=a*a%MOD;
        n>>=1;
    }
    return ans;
}
long long inv(long long a)
{
    return quick_pow(a,MOD-2);
}
int main()
{
    long long n;
    long long ans=0;
    long long c=inv(2);
    while(~scanf("%I64d",&n))
    {
        for(long long i=1,j; i<=n; i=j+1)
        {
            j=n/(n/i);
            long long d=(n/i)%MOD;
            long long m=(j-i+1)%MOD;
            long long a1=(n-d*i)%MOD;
            ans+=(m*a1-(m-1)%MOD*m%MOD*c%MOD*d%MOD)%MOD;
            ans%=MOD;
           // cout<<i<<"->"<<j<<"="<<ans<<endl;
        }
        cout<<ans<<endl;
    }
    return 0;
}
//995921
//87448611


你可能感兴趣的:(C++,ACM)