《算法竞赛进阶指南》0x32 T2 余数之和

题目传送门

题目描述

给出正整数 n n n k k k,计算 ( k m o d 1 ) + ( k m o d 2 ) + ( k m o d 3 ) + … + ( k m o d n ) (kmod1)+(k mod 2)+(k mod 3)+…+(k mod n) (kmod1)+(kmod2)+(kmod3)++(kmodn)的值。

输入格式

输入仅一行,包含两个整数 n n n k k k

输出格式

输出仅一行,即 ( k m o d 1 ) + ( k m o d 2 ) + ( k m o d 3 ) + … + ( k m o d n ) (kmod1)+(k mod 2)+(k mod 3)+…+(k mod n) (kmod1)+(kmod2)+(kmod3)++(kmodn)的值。

数据范围

1 ≤ n , k ≤ 1 0 9 1≤n,k≤10^9 1n,k109

输入样例

5 3

输出样例

7

题解 O ( k ) O(\sqrt k) O(k )

很简单的一个道理 k k k% i i i= k − ⌊ k / i ⌋ × i k-\lfloor k/i\rfloor \times i kk/i×i
所以题目要求的式子就可以转化为 n × k − n\times k- n×k ∑ i = 1 n ⌊ k / i ⌋ × i \sum_{i = 1}^{n}\lfloor k/i\rfloor \times i i=1nk/i×i

接下来我们拿n= 9 ,k = 4 为例分析下k/i:
  4/1 4/2 4/3 4/4 4/5 4/6 4/7 4/8 4/9
  4  2  1  1  0  0  0  0  0
所以最后的结果就是
9 ∗ 4 − 4 ∗ 1 − 2 ∗ 2 − 1 ∗ ( 3 + 4 ) − 0 ∗ ( 5 + 6 + 7 + 8 + 9 ) 9*4-4*1-2*2-1*(3+4)-0*(5+6+7+8+9) 9441221(3+4)0(5+6+7+8+9)
用l和r来表示一个连续区间的左端点和右端点,再通过等差数列通项公式 ( l + r ) ∗ ( r − l + 1 ) / 2 (l+r)*(r-l+1)/2 (l+r)(rl+1)/2求出这一段数字的总和再乘上 ( k / l ) (k/l) (k/l)
通过以上这种方式就可以避免遍历 1 − n 1-n 1n,大大减少循环次数

code
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,k;
	cin>>n>>k;
	int r;
	long long ans;
	ans=(long long)n*k;
	for(int l=1;l<=n;l=r+1)
	{
		if(k/l==0) break;//超出范围,退出循环
		r=min(k/(k/l),n);//求出右端点,再与n求最小值,防止超出范围
		ans-=(long long)(k/l)*(l+r)*(r-l+1)/2;//公式
	}
	cout<<ans;
	return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值