P2261 余数求和(整除分块)

\sum^{n}_{i=1}(k\ mod\ i)=\sum _{i=1}^{n}(k-\left \lfloor \frac{k}{i} \right \rfloor\times i)=n\times k- \sum^{n}_{i=1}(i\times \left \lfloor \frac{k}{i} \right \rfloor)\;\;\;O(2\sqrt{k})

1.其中i从1增加到n为等差数列,\left \lfloor \frac{k}{i} \right \rfloor  的值随i的增加具有阶梯性(下降),故可将其分为一个一个台阶进行计算。即整除分块

对于一个  \left \lfloor \frac{k}{i_{1}} \right \rfloor  ,值与其相同的最后一个 \left \lfloor \frac{k}{i_{2}} \right \rfloor   有i_{2}=\left \lfloor \frac{k}{\left \lfloor \frac{k}{i_{1}} \right \rfloor} \right \rfloor  ,利用该性质对每个台阶左端点i_{1}可求出台阶右端点i_{2}

2.对于每个台阶,\left \lfloor \frac{k}{i} \right \rfloor 相同,i的值为等差数列,设l,r分别为台阶左、右端点。每个台阶的值 :\sum^{l}_{i=r}(i\times \left \lfloor \frac{k}{i} \right \rfloor)= \left \lfloor \frac{k}{i} \right \rfloor \times \sum_{i=r}^{l}i= \left \lfloor \frac{k}{i} \right \rfloor \times \frac{(l+r)\times(r-l+1)}{2}

3.ans=n*k-所有台阶的值之和。

注意判断\frac{k}{i}=0的情况,以及台阶右端点不能大于n。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int main()
{
    //freopen("1.txt","r",stdin);
    ll n,k,ans;
    scanf("%lld%lld",&n,&k);
    ll l,r;
    ans=n*k;
    for(ll i=1;i<=n;)
    {
    if(k/i==0)
        break;
    r=min(k/(k/i),n);
    ans-=(i+r)*(r-i+1)/2*(k/i);
        i=r+1;
  //  cout<<1<<endl;
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值