数论、关于余数之和的浅解

求余数之和问题

就相当于一个n和k,将k对1~n的数分别求余数,然后求出来和是多少,其表达公式如j(n,k)=k%1+k%2+k%3+…+k%n

   单单暴力的话,时间上非常浪费,所以这个时候引用数论里面的一些基础知识。用数学思想将这个题简化。

  核心公式为:k%i = k -  ⌊ k / i ⌋ *  i。  (下取整符号)

  所有原式就可以写成

 

  所以这个时候只需要看一下 k / i 下取整的结果。在这个地方可以采用打表思想,进行观察。

    当n = 20 k = 10 的时候,观察k/i 会发现,会有一块儿一块儿值是相等的,然后如果该值相等的序列就是一个等比数列,可以直接进行求和公式计算,这样会省很多时间,所以只需要找每一块儿的左右边界,遇到的第一个位置可以默认为是左边界,那么右边界怎么求,通过观察会发现,右边界 R = k / (k/i) 。左右边界都有了之后就非常简单了。

   只需要遍历一遍,找到每一块儿的左右边界,直接计算出来每一块儿的和,然后记得把 i 直接更新为右边界,因为这一块儿已经计算过了。

  但是还有一个问题需要注意,就是 k / i 等于 0 的时候 ,当等于 0 的时候,通过公式可以发现,之后就没必要再进行了,因为后面全是 0 。就可以直接结束了。

  

基本原理弄明白了就可以看题了。

AcWing199. 余数之和

给出正整数 n和 k,计算 j(n,k)=kmod1+kmod2+kmod3+…+kmodn的值。

例如 j(5,3)=3mod1+3mod2+3mod3+3mod4+3mod5=0+1+0+3+3=7。

输入格式

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

输出格式

    输出仅一行,即 j(n,k)。

数据范围

    1≤n,k≤109

输入样例:

5 3

输出样例:

7

 代码:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

int main(void)
{
	ll n,k;

    cin>>n>>k;

    ll sum=n*k; // 通过公式推导出来的,该数为基数,然后减去对应的数就行了。

	for(ll i=1;i<=n;i++) // 一共有n个数需要求余累加
 	{
		ll l=i,r,s=k/i;//  l 为左边界, r 为右边界, s 为k/i下取整值。

		if(k/i==0) break;//如果 为0 直接结束

		r=min(n,k/s);//如果右边界在所求的范围之外,则更新一下。

		sum-=s*((l+r)*(r-l+1)/2); // sum 减去这一块儿的值。

		i=r;//更新 i 值,跳过这一块儿。
	}

	cout<<sum;//输出结果。

	return 0;
 } 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值