余数(数论分块)

Posted harrypotter-fan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了余数(数论分块)相关的知识,希望对你有一定的参考价值。

题目描述:

技术图片

 

题解:

首先容易想到:当 i > n 时,n mod i = n

所以如果 m > n , 

  ans+=((m-n)%mod)*(n%mod)%mod;

  m=n;

接下来考虑 i<=n 的情况:

技术图片

后面这个东西很明显可以用数论分块算,时间复杂度是O(sqrt(N))

但我当时做的时候还没有学数论分块,所以代码十分丑陋

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,m,ans;
ll l,r,h,t,cnt,sum;
int main()
    scanf("%lld%lld",&n,&m);
    if(n<=m)
        ans+=((m-n)%mod)*(n%mod)%mod;
        ll sq=sqrt(n);
        for(ll i=1;i<=n/(sq+1);i++)
            ans=(ans+(n%i))%mod;//这一区间内的n%i没有特殊规律,只能硬算
        for(ll i=sq;i>0;i--)//此处i表示除完以后向下取整的结果 
            l=n/(i+1)+1;r=n/i;//用n除以[l,r]区间内的数取整完结果均为i
            //统计 n mod 这些数的余数就是求等差数列:n-i*l,n-i*(l+1),...,n-i*r 的和  
            h=n-l*i,t=n-r*i;//首项,末项 
            cnt=r-l+1,sum=h+t;//项数,首项加末项的和 
            if(cnt&1ll)sum>>=1;
            else cnt>>=1;//除以2 
            if(l<=r) ans=(ans+(cnt%mod)*(sum%mod))%mod;
         
    
    else
        ll sq=sqrt(n);//基本同上 
        if(m<=(n/(sq+1)))
            for(ll i=1;i<=m;i++)
                ans=(ans+(n%i))%mod;
        
        else
            for(ll i=1;i<=n/(sq+1);i++)
                ans=(ans+(n%i))%mod;
            for(ll i=sq;i>0;i--)
                l=n/(i+1)+1;r=n/i;
                if(r>=m) r=m;
                h=n-l*i,t=n-r*i;
                cnt=r-l+1,sum=h+t;
                if(cnt&1ll)sum>>=1;
                else cnt>>=1;
                if(l<=r) ans=(ans+(cnt%mod)*(sum%mod))%mod;
                if(r==m) break;
            
        
    
    printf("%lld",ans);
    return 0;

以上是关于余数(数论分块)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1257余数之和(数论分块,暴力)

bzoj 1257 [CQOI2007]余数之和——数论分块

luogu2261余数求和题解--整除分块

[CQOI2007]余数求和-整除分块

数论分块之整除分块

数论分块 数学