51Nod 1225 余数之和 [整除分块]

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注
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

这种东西莫比乌斯已经用过很多次了本来看到了想十分钟写完行了不发Blog结果WA的太惨了!!!
做法很简单,余数=n-[n/i]*i
然后一整理整除分块+等比数列搞就行了
问题:
1.等比数列/2要用逆元,只用到2的逆元所以先算出来直接用就好了,否则会T
2.一定要小心,n*n也会爆ll,所以(n%MOD)&(n%MOD),括号不能丢,因为10^9*10^12也会爆ll
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath> 
using namespace std; 
typedef long long ll; 
const ll MOD=1e9+7;
ll n,ans,r,Inv2;
ll Pow(ll a,int b){
    ll re=1;
    for(;b;b>>=1,a=a*a%MOD)
        if(b&1) re=re*a%MOD;
    return re;
}
ll calc(ll l,ll r){return ((l+r)%MOD)*((r-l+1)%MOD)%MOD*Inv2%MOD;}
int main(){
    //freopen("in","r",stdin);
    Inv2=Pow(2,MOD-2);
    scanf("%lld",&n);
    for(ll i=1;i<=n;i=r+1){
        r=n/(n/i);
        ans=(ans+(n/i)%MOD*calc(i,r)%MOD)%MOD;
    }
    n%=MOD;
    printf("%lld",(n*n%MOD-ans+MOD)%MOD); 
}

 





posted @ 2017-02-05 14:55  Candy?  阅读(278)  评论(0编辑  收藏  举报