P2261 [CQOI2007]余数求和

Problem:给定n,k(n,k\leq 10^{9}),求\sum_{i=1}^{k}nMODi 。

标签:高中数学题(一元一次不等式+等差数列求和)

首先我们考虑:当k>n时,\sum_{i=n+1}^{k}nMODi=\sum_{i=n+1}^{k}n=(k-n)\times n。对于这部分单独处理即可。

现在我们考虑k<n的情况(k=n时显然答案是0)

对于被除数n和除数xnMODx=i\Leftrightarrow kx+i=n(k,x,i\in N)。我们现在考虑的就是如何快速累加i

显然,假定k不随x的变化而变化时,x+1i-=k。反之,x-1i+=k

所以,x在某个特定的范围内(前提是k不变)变换时,x在这些取值下的出i可以通过求等差数列(公差为k)的方法求出。

举个例子:

n=39,k=39时:当除数(模数)取20,21,22...37,38,商均为1,余数就是19,18,17,16,15,14.....3,2,1,是一个公差为1的等差数列。

问题来了:如何求出上面说的x的“特定范围”?

让我们先看之前那个式子:

nMODx=i\Leftrightarrow kx+i=n(k,x,i\in N)

假设k是确定的,我们根据x,i的定义,可知:0\leq i< x

又由kx+i=n,得:kx+x-1\geq n

\therefore x\geq \frac{n+1}{k+1}

现在我们再确定x的上界:当以上式子nMODx=i\Leftrightarrow kx+i=n(k,x,i\in N)kk-1时,有:

(k-1)x+i=n\Leftrightarrow x\geq \frac{n+1}{k}

\therefore在式子kx+i=n中,\frac{n+1}{k+1}\leq x< \frac{n+1}{k}

也就是说:我们可以通过枚举k,从而求出对应模数x的范围,在此时求出来的模数x的范围内,余数i的变化规律呈等差数列分布。这样我们便可以利用等差数列通项公式来O(1)求了。

Code:

#include<cstdio>
#include<iostream>
using namespace std;

long long n,k,xj,fst,lst,tot,minn,ans;

int main()
{
    scanf("%lld%lld",&k,&n);
    if(n<=k)
    {
        ans=(k-n)*n;
        k=n-1;
    }
    xj=n/k;
    for(long long a=xj;a<=n;a++)
    {
        minn=(n+1)/(a+1);
        if(k<=100000)	break;
        //当k取到10万左右时,x的值域涵盖的整数就很少了,这时直接暴力累加答案即可。
        if((n+1)%(a+1)>0)  minn+=1;
        fst=n%k,lst=n%minn;
        tot=(lst-fst)/a+1;
        ans+=tot*fst+a*tot*(tot-1)/2;
        k=minn-1;
    }
    for(long long i=1;i<=k;i++)	 ans+=n%i;
    cout<<ans;
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值