数论基础之分块

数论分块


(一)提出问题

∑ i = 1 n ⌊ N i ⌋ \sum_{i=1}^n{\lfloor {N\over i}\rfloor} i=1niN
暴力?


(二)做法

1.显然可以使用 O ( N ) O(N) ON的做法暴力过去,但是数据大了肯定就凉了
2.如果取N=10的话
可以发现 N / i N/i N/i的值分别是10,5,3,2,2,1,1,1,1,1
这些相同的数字岂不是可以使用区间长度×相同的数字来直接计算吗,然后遍历过程中就能把变量i直接移到下一个位置(具体是哪里后续会解释)


(三)右端点位置的证明

现在给出一个左端点i,那么它的最大右端点 i 1 i_1 i1是多少,可以使得对于任意的 ( i ≤ x ≤ i 1 ) (i\leq x \leq i_1) (ixi1),都有 ⌊ N x ⌋ = ⌊ N i ⌋ \lfloor {N\over x} \rfloor=\lfloor {N\over i} \rfloor xN=iN

事实上: i 1 = ⌊ N ⌊ N i ⌋ ⌋ i_1=\lfloor {N\over {\lfloor {N\over i} \rfloor}} \rfloor i1=iNN

证明显然不是自己会证明的 ):
⌊ N i ⌋ = k \lfloor {N\over i }\rfloor=k iN=k,则根据定义可以写成 N = k i + r , ( 0 ≤ r < i ) N=ki+r,(0\leq r<i) N=ki+r,(0r<i)
⌊ N i + d ⌋ = k \lfloor {N\over {i+d}} \rfloor=k i+dN=k,同理可得 N = k i + k d + r 1 , ( 0 ≤ r 1 < i ) N=ki+kd+r_1,(0\leq r_1<i) N=ki+kd+r1,(0r1<i)

显然我们只需求出 d m a x = ⌊ r − r 1 k ⌋ = ⌊ r k ⌋ d_{max}=\lfloor {{r-r_1}\over k} \rfloor=\lfloor{r\over k}\rfloor dmax=krr1=kr

i 1 = i + d m a x i_1=i+d_{max} i1=i+dmax

= i + ⌊ r k ⌋ =i+\lfloor {r\over k}\rfloor =i+kr

= i + ⌊ N % i ⌊ N i ⌋ ⌋ =i+\lfloor{{N\%i}\over {\lfloor {N\over i }\rfloor}}\rfloor =i+iNN%i

= i + ⌊ N − ⌊ N i ⌋ i ⌊ N i ⌋ ⌋ =i+\lfloor{{N-\lfloor {N\over i}\rfloor}i\over {\lfloor {N\over i }\rfloor}}\rfloor =i+iNNiNi

= ⌊ i + N − ⌊ N i ⌋ i ⌊ N i ⌋ ⌋ =\lfloor{i+{{N-\lfloor {N\over i}\rfloor}i\over {\lfloor {N\over i }\rfloor}}}\rfloor =i+iNNiNi

合并同类项后得?

= ⌊ N ⌊ N i ⌋ ⌋ =\lfloor {N\over {\lfloor {N\over i} \rfloor}} \rfloor =iNN


(四)复杂度分析

其实循环的次数就是 ⌊ N i ⌋ \lfloor {N\over i}\rfloor iN的不同的值的个数,即分块的个数

那么有多少个不同的数,对于一个N,可以分成两种情况考虑:
1.当 i ≤ N i\leq \sqrt{N} iN 的时候,最多也只有i的范围长度即 n \sqrt{n} n 种可能性
2.当 i > N i>\sqrt{N} i>N 时, ⌊ N i ⌋ < n \lfloor {N\over i}\rfloor <\sqrt{n} iN<n ,最多只有范围长度 n \sqrt{n} n 种情况

综上,分块个数不会超过 2 n 2\sqrt{n} 2n 个,即时间复杂度 O ( n ) O(\sqrt{n}) O(n )


(五)核心代码

ll ans=0;
for (int l=1,r=0;l<=n;l=r+1)
//每次左端点在前一个区间的右端点的下一个位置r+1
{
     r=n/(n/l);//右端点
     ans+=(r-l+1)*(n/l);
}

(六)例题

1.洛谷 P1403 板子题
题意:求出1-N的每个数的因数总和
做法:实际上并不用打表算,只要算 ∑ i = 1 n ⌊ N i ⌋ \sum_{i=1}^n{\lfloor {N\over i}\rfloor} i=1niN,即找出N个数中有多少个数字是含有因数i的,例如7/3=2,所以3和6是含有因数3的,则答案就加上2

int main()
{
    ll ans=0;
    ll n;
    scanf("%lld",&n);
    for (ll l=1,r=0;l<=n;l=r+1)
    {
        r=n/(n/l);
        ans+=(r-l+1)*(n/l);
    }
    WW(ans);
    return 0;
}

2.[CQOI2007]余数求和

题意:给出n,k,求 ∑ i = 1 n ( k   m o d   i ) \sum_{i=1}^n(k \ mod \ i) i=1n(k mod i)
做法:考虑到模数并不能直接套,于是进行如下转化

∑ i = 1 n ( k   m o d   i ) \sum_{i=1}^n(k \ mod \ i) i=1n(k mod i)

= ∑ i = 1 n ( k − ⌊ k i ⌋ i ) =\sum_{i=1}^n(k-\lfloor {k\over i} \rfloor i) =i=1n(kiki)

= n k − ∑ i = 1 n i ⌊ k i ⌋ =nk-\sum_{i=1}^ni\lfloor {k\over i} \rfloor =nki=1niik

这就很好做了,将 ⌊ k i ⌋ \lfloor {k\over i} \rfloor ik的值相同的分为一块,然后 ( l ≤ i ≤ r ) (l\leq i \leq r) (lir)就相当于是一个✖上一个定值的等差数列了

	for(ll i=1,r;i<=n;i=r+1)
	{	
		if(k/i) r=min(k/(k/i),n);//不判的话会出现除0的错误
		else r=n;
		ans-=(k/i)*(r-i+1)*(i+r)/2;
	}	

尚不深究……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值