【分块】余数求和

传送门

【题目】:

给你n,k;        \large \sum_{i=1}^{n}k\%n 

【题解】:

根据多个人的博客,我终于看懂了,其实就很简单,大家认真分析即可。

首先对这个式子进行一系列地化简:

\large \sum_{i=1}^{n}k\%n=\sum_{i=1}^{n}(k-\left \lfloor \frac{k}{i} \right \rfloor*i)

\large \sum_{i=1}^{n}(k-\left \lfloor \frac{k}{i} \right \rfloor*i)=n*k-\sum_{i=1}^{n}\left \lfloor \frac{k}{i} \right \rfloor*i

 

发现每一个位置i,整除k都会得到不同的值。

然后对于不同的值,进行分块处理。

对于每一块来说,都有左右端点。左端点L=i,那么右端点呢???

∵k/L=k/R

∴R=k/(k/L)

可能会出现k/L=0,此时加一个判断直接让R=n.

区间求和:等差数列求和。

暂存值:t=k/L

个数为:R-L+1

那么一段区间的值为:t*(R-L+1)*(L+R)/2

看代码呗;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,ans;
int main()
{
    ios_base :: sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n >> k;

    for ( int L=1 , R ; L<=n ; L=R+1 ){
        ll tmp = k/L;
        R = tmp ? min( k/tmp , n) : n;
        ans = ans + tmp* ( R - L + 1 )*(L+R)/2;
    }
    ans = n*k - ans;
    cout<<ans<<endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值