数论分块(整除分块)

前言:

断更太久,已经忘了博客怎么写了。。
这篇博客用来介绍带整除式子的快速求解办法。
 

符号说明:

⌊ a b ⌋ \left \lfloor \frac{a}{b}\right \rfloor ba  a a a除以 b b b向下取整。
⌈ a b ⌉ \left \lceil \frac{a}{b}\right \rceil ba  a a a除以 b b b向上取整。
∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) i=1nf(i)   累加符号,表示 f ( 1 ) + f ( 2 ) + … + f ( n ) f(1)+f(2)+…+f(n) f(1)+f(2)++f(n)
 
 

问题:

求解 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}\left \lfloor \frac{n}{i}\right \rfloor i=1nin,其中 1 ⩽ n ⩽ 1 e 12 1\leqslant n \leqslant 1e12 1n1e12
 

正文:

首先,不难发现有一个o(n)的暴力。
我们需要一个 n \sqrt{n} n 的做法。
 
我们可以先举例观察,我们举 n = 10 n=10 n=10,然后枚举从 1 1 1 n n n枚举 i i i,观察 ⌊ n i ⌋ \left \lfloor \frac{n}{i}\right \rfloor in的值。
 

1 1 1    2 2 2    3 3 3    4 4 4    5 5 5    6 6 6    7 7 7    8 8 8    9 9 9    10 10 10
10 10 10 5 5 5    3 3 3    2 2 2    2 2 2    1 1 1    1 1 1    1 1 1    1 1 1    1 1 1

 
就是上面这个样子。
不难发现也不难证明,相同的数都是连续的,可以把它分成一块一块值相同的段。那么我们可以利用这个性质,对于每一块,将这个块的数字乘上块的长度,就可以求解这一块的和了。
 
现在还有两个问题要解决。
一个是块的数量,一个是如何快速找到块的两端
 
首先块的数量,对于 i i i 1 1 1 n n n取值, ⌊ n i ⌋ \left \lfloor \frac{n}{i}\right \rfloor in的值的种数不会超过 2 n 2\sqrt{n} 2n ,也就是块的数量不会超过 2 n 2\sqrt{n} 2n
证明其实很容易,
嗯,可以证,前 n \sqrt{n} n i i i最多有 n \sqrt{n} n 种值,而当 i i i大于 n \sqrt{n} n 时,取值一定小于 n \sqrt{n} n ,所以不超过 2 n 2\sqrt{n} 2n (摘自ztc口糊)。

 
那么第二个问题,快速找到块的端点
当某一块的左端点为 l l l,那么它的右端点 r r r就是 ⌊ n ⌊ n l ⌋ ⌋ \left \lfloor \frac{n}{\left \lfloor \frac{n}{l}\right \rfloor}\right \rfloor lnn 这个就更好证了。
也可以理解成,已知 i i i,那么与 i i i相同的块的右端点就是 ⌊ n ⌊ n i ⌋ ⌋ \left \lfloor \frac{n}{\left \lfloor \frac{n}{i}\right \rfloor}\right \rfloor inn
也就是说,当 i i i的取值在 l l l r r r之间时,式子的结果是一样的,那么只要再乘上区间长度 ( r − l + 1 ) (r-l+1) (rl+1)即可。

最后再对于原问题,上模板代码:(有取模的加取模)

ll ans=0;
for(ll l=1,r;l<=n;l=r+1)
{
	r=n/(n/l);
	ans+=(r-l+1)*(n/l);
}

 
 

例题及应用:

再拓展几个例题,有,但不全,还是要去多找题做。

问题1:

已知 w w w n n n,求解 ∑ i = 1 n ⌊ w i ⌋ \sum_{i=1}^{n}\left \lfloor \frac{w}{i}\right \rfloor i=1niw,其中 1 ⩽ n , w ⩽ 1 e 12 1\leqslant n,w \leqslant 1e12 1n,w1e12

解:

与原题不同,这里的枚举上界 n n n不再作为被除数。
那么在计算右端点 r r r的时候,会引发一个细节问题。
看式子, r = w / ( w / l ) r=w/(w/l) r=w/(w/l)。会出现两个种特殊情况。
一种是 w / l = = 0 w/l==0 w/l==0,此时再调用这个式子就会出现除 0 0 0的情况,导致RE。
还有一种是,计算结果 r > n r>n r>n,此时右端点不在边界内了。
要把这两种情况考虑进去,在原代码的基础上进行修改。

ll ans=0;
for(ll l=1,r;l<=n;l=r+1)
{
	if(w/l)r=w/(w/l);
	else r=n;
	r=min(r,n);
	ans+=(r-l+1)*(w/l);
}

 
 

问题2:

已知 a , b a,b a,b n n n,求解 ∑ i = 1 n ⌊ a i ⌋ ⌊ b i ⌋ \sum_{i=1}^{n}\left \lfloor \frac{a}{i}\right \rfloor\left \lfloor \frac{b}{i}\right \rfloor i=1niaib,其中 1 ⩽ n , a , b ⩽ 1 e 12 1\leqslant n,a,b \leqslant 1e12 1n,a,b1e12

解:

在原问题的基础上多乘了一个,不过别怕,只不过从原来 2 a 2\sqrt{a} 2a 个断点,变成了 2 a + 2 b 2\sqrt{a}+2\sqrt{b} 2a +2b 个断点,复杂度仍然是根号级别的。
我们只要每次找最近的那个断点即可。

ll ans=0;
for(ll l=1,r,r1,r2;l<=n;l=r+1)
{
	if(a/l)r1=a/(a/l);
	else r1=n;
	if(b/l)r2=b/(b/l);
	else r2=n;
	r=min(r1,r2)
	r=min(r,n);
	ans+=(r-l+1)*(a/l)*(b/l);
}

 
 

问题3:

已知 w w w n n n,求解 ∑ i = 1 n ⌈ w i ⌉ \sum_{i=1}^{n}\left \lceil \frac{w}{i}\right \rceil i=1niw,其中 1 ⩽ n , w ⩽ 1 e 12 1\leqslant n,w \leqslant 1e12 1n,w1e12

解:

这是向上取整的,不好找到想原来一样的结论,但是我们可以把向上取整转化为向下取整。
⌈ w i ⌉ = ⌊ w + i − 1 i ⌋ = ⌊ w − 1 i ⌋ + 1 \left \lceil \frac{w}{i}\right \rceil=\left \lfloor \frac{w+i-1}{i}\right \rfloor=\left \lfloor \frac{w-1}{i}\right \rfloor+1 iw=iw+i1=iw1+1
就可以轻松解决了。

ll ans=0;
for(ll l=1,r;l<=n;l=r+1)
{
	if((w-1)/l)r=(w-1)/((w-1)/l);
	else r=n;
	r=min(r,n);
	ans+=(r-l+1)*((w-1)/l+1);
}

 
 

问题5:

已知 w w w n n n,求解 ∑ i = 1 n i ⌊ w i ⌋ \sum_{i=1}^{n}i\left \lfloor \frac{w}{i}\right \rfloor i=1niiw,其中 1 ⩽ n , w ⩽ 1 e 12 1\leqslant n,w \leqslant 1e12 1n,w1e12

解:

多乘了一个 i i i,与原来不同的就是,这次我们不能再乘 r − l + 1 r-l+1 rl+1了,前面 r − l + 1 r-l+1 rl+1的本质其实是那一段的区间和,这时候我们要乘上的是区间 i i i的求和。(因为这段区间里 ⌊ w i ⌋ \left \lfloor \frac{w}{i}\right \rfloor iw是一样的,相当于一个常系数,所以才可以这么乘的)

ll ans=0;
for(ll l=1,r;l<=n;l=r+1)
{
	if(w/l)r=w/(w/l);
	else r=n;
	r=min(r,n);
	ans+=(r-l+1)*(l+r)/2*(w/l);
}

 
 

问题6:模和积

∑ i = 1 n ∑ j = 1 m ( n    m o d    i ) × ( m    m o d    j ) , i ≠ j \sum_{i=1}^{n}\sum_{j=1}^{m}(n\;mod\;i)\times (m\;mod\;j),i\neq j i=1nj=1m(nmodi)×(mmodj),i=j 19940417 19940417 19940417的值。
其中 1 ⩽ n , m ⩽ 1 e 9 1\leqslant n,m \leqslant 1e9 1n,m1e9

解:

首先要知道 ( n    m o d    i ) = n − i × ⌊ w i ⌋ (n\;mod\;i)=n-i\times \left \lfloor \frac{w}{i}\right \rfloor (nmodi)=ni×iw
然后开始化式子,注意 i ≠ j i\neq j i=j的条件不能忽略。
在这里插入图片描述
化好公式后,就可以写了。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const ll mod=19940417;
typedef pair<int,int> P;
const ll MAXN=1000000;

const ll inv6=3323403;
ll sum(ll l,ll r,ll flag)
{
    if(flag==1)
    {
        return (r-l+1)*(l+r)/2%mod;
    }
    else
    {
        return (r*(r+1)%mod*(2*r+1)%mod*inv6%mod-(l-1)*l%mod*(2*l-1)%mod*inv6%mod+mod)%mod;
    }
}

int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    ll sum1=0;
    for(ll l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        sum1=(sum1+n*(r-l+1)%mod-sum(l,r,1)*(n/l)%mod+mod)%mod;
    }
    ll sum2=0;
    for(ll l=1,r;l<=m;l=r+1)
    {
        r=m/(m/l);
        sum2=(sum2+m*(r-l+1)%mod-sum(l,r,1)*(m/l)%mod+mod)%mod;
    }
    ll nm=min(n,m);
    ll sum3=0;
    for(ll l=1,r,r1,r2;l<=nm;l=r+1)
    {
        if(n/l)r1=n/(n/l);
        else r1=nm;
        if(m/l)r2=m/(m/l);
        else r2=nm;
        r=min(r1,r2);
        r=min(r,nm);
        sum3=(sum3+n*m%mod*(r-l+1)%mod-(n*(m/l)%mod+m*(n/l)%mod)*sum(l,r,1)%mod+sum(l,r,2)*(n/l)%mod*(m/l)%mod+mod)%mod;
    }
    ll ans=(sum1*sum2-sum3+mod)%mod;
    printf("%lld\n",ans);
    return 0;
}

 
 

问题7:余数求和
解:

问题6的简化版本,就不贴代码了。

  • 10
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值