【ybtoj高效进阶6-2-5】余数之和/【luogu】P2261 [CQOI2007] 余数求和【 数论】【整除分块】

【ybtoj高效进阶6-2-5】余数之和 /【luogu P2261】 [CQOI2007] 余数求和

题目大意:

给定 n n n , k k k,求 ∑ i = 1 n k   m o d   i \sum\limits_{i=1}^{n}k \bmod i i=1nkmodi

思路:

先来分析一下整除分块这种东西
根据取模运算的性质, x   m o d   y = x − y ∗ ⌊ x y ⌋ x\bmod y=x-y*\left \lfloor \frac{x}{y} \right \rfloor xmody=xyyx
则原式= ∑ i = 1 n k − i ∗ ⌊ i k ⌋ = n ∗ k − ∑ i = 1 n i ∗ ⌊ i k ⌋ \sum\limits_{i=1}^{n}k-i*\left \lfloor \frac{i}{k} \right \rfloor=n*k-\sum\limits_{i=1}^{n}i*\left \lfloor \frac{i}{k} \right \rfloor i=1nkiki=nki=1niki
右半部分可以使用整除分块处理

整除分块:

第一个结论:对于 a , b , c ∈ Z a,b,c\in Z a,b,cZ ⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋ \left \lfloor \frac{a}{bc} \right \rfloor=\left \lfloor \frac{\left \lfloor \frac{a}{b} \right \rfloor}{c} \right \rfloor bca=cba
证明:
a b = ⌊ a b ⌋ + x , x ∈ [ 0 , 1 ) \frac{a}{b}=\left \lfloor \frac{a}{b} \right \rfloor+x,x\in[0,1) ba=ba+x,x[0,1)
∵ ⌊ a b c ⌋ = ⌊ a b ∗ 1 c ⌋ = ⌊ 1 c ∗ ( ⌊ a b ⌋ + x ) ⌋ = ⌊ ⌊ a b ⌋ c + x c ⌋ \because\left \lfloor \frac{a}{bc} \right \rfloor=\left \lfloor \frac{a}{b} *\frac{1}{c}\right \rfloor=\left \lfloor \frac{1}{c} *(\left \lfloor \frac{a}{b} \right \rfloor+x)\right \rfloor=\left \lfloor \frac{\left \lfloor \frac{a}{b} \right \rfloor}{c}+\frac{x}{c} \right \rfloor bca=bac1=c1(ba+x)=cba+cx

显然 x c < 1 \frac{x}{c}<1 cx<1, 对答案没有影响,直接舍去即可
然后就可以开始愉快的分块了

对于 ⌊ n i ⌋ = ⌊ n j ⌋ , 0 < i ≤ j ≤ n \left \lfloor \frac{n}{i} \right \rfloor=\left \lfloor \frac{n}{j} \right \rfloor,0<i\leq j\leq n in=jn,0<ijn
这时候我们要找到最大的 j j j
k = ⌊ n i ⌋ k=\left \lfloor \frac{n}{i} \right \rfloor k=in,则有 k ≤ n i k\leq\frac{n}{i} kin
∴ ⌊ n k ⌋ ≥ ⌊ n n i ⌋ = ⌊ i ⌋ = i \therefore \left \lfloor \frac{n}{k} \right \rfloor\geq\left \lfloor \frac{n}{\frac{n}{i}} \right \rfloor=\left \lfloor i\right \rfloor=i kninn=i=i
∴ j = m a x , i m a x = i = ⌊ n k ⌋ = ⌊ n ⌊ n i ⌋ ⌋ \therefore j=max,i_{max}=i=\left \lfloor \frac{n}{k} \right \rfloor=\left \lfloor \frac{n}{\left \lfloor \frac{n}{i} \right \rfloor} \right \rfloor j=max,imax=i=kn=inn
Q E D QED QED
那么对于 ⌊ n i ⌋ \left \lfloor \frac{n}{i} \right \rfloor in相同的多个 i i i 我们就可以打包计算了, ⌊ n i ⌋ \left \lfloor \frac{n}{i} \right \rfloor in最多只有 n \sqrt{n} n 种情况(显然我不会证明
那么整个算法的时间复杂度就是 O ( n ) O(\sqrt n) O(n )

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<ctime>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
ll n,k; 
inline ll in()
{
	ll res=0,f=1;
	char ch;
	while((ch=getchar())<'0'||ch>'9')
	 if(ch=='-') f=-1;
	res=res*10+ch-48;
	while((ch=getchar())>='0'&&ch<='9')
	 res=res*10+ch-48;
	return res*f;
}
int main()
{
	n=in(),k=in();
	ll ans=n*k;
	for(r ll i=1,j;i<=n;i=j+1)
	{
		j=((k/i)==0)?n:min(n,k/(k/i)); //结论
		ans-=(k/i)*(j-i+1)*(i+j)>>1;//k/i 是值,(j-i+1)*(i+j)/2 等差数列的求和公式,好好理解
	}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值