zoukankan      html  css  js  c++  java
  • CQOI2007 余数之和

    Time Limit: 5 Sec Memory Limit: 128 MB

    Description

    给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值
    其中k mod i表示k除以i的余数。
    例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

    Input

    输入仅一行,包含两个整数n, k。
    1<=n ,k<=10^9

    Output

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

    Sample Input

    5 3
    

    Sample Output

    7
    

    简要题解

    我们可以把原式数学化一下:求(sum limits_{i=1}^n k mod i)
    我们可以发现

    [egin{align*} ext{原式}&=sum limits_{i=1}^n k mod i\ &=sum limits_{i=1}^n k- lfloor frac ki floor cdot i\ &=nk - sum limits_{i=1}^n lfloor frac ki floor cdot i end{align*} ]

    显然,只要(lfloor frac ki floor)的值在一段段i的范围内是一样的。我们的任务就是要求出每一段这样的范围。我们令(f(x)=lfloor frac kx floor qquad g(x)=lfloor frac k{lfloor frac kx floor} floor),那么其实直觉就可以告诉我们(g(x))就可以表示f值=(lfloor frac kx floor)的最大的数。然而数学毕竟是一门严谨的科学,我们可能需要来证明一下。
    显然(lfloor frac kx floor leq frac kx),那么(g(x)=lfloor frac k{lfloor frac kx floor} floor geq lfloor frac k{frac kx } floor = x ext{即} g(x) geq x)。所以有(lfloor frac k{g(x)} floor leq lfloor frac kx floor)
    同时,(lfloor frac k{g(x)} floor = lfloor frac k{lfloor frac k{lfloor frac kx floor} floor} floor geq lfloor frac k{ frac k{lfloor frac kx floor} } floor = lfloor frac kx floor),即(lfloor frac k{g(x)} floor geq lfloor frac kx floor)(lfloor frac k{g(x)} floor leq lfloor frac kx floor),所以(lfloor frac k{g(x)} floor = lfloor frac kx floor)
    所以(forall i in [x,lfloor frac k{lfloor frac kx floor} floor])(lfloor frac ki floor)的值都相等!其实之前的猜想的“最大”是很显然的,也没必要再去证一遍了,就算不是最大的,也不影响我们的这个程序。
    下面我们就有了一个算法:统计([1,g(1)])的区间里的(lfloor frac ki floor cdot i)的和,既然(lfloor frac ki floor)都一样,那就用等差数列求和公式来算一下即可。然后在从(g(1)+1)(g(g(1)+1))这段区间再如此统计……重复上述步骤,直到(i>k),此时(lfloor frac ki floor)一定等于0,直接令g(i)=n,统计i..n即可。
    下面我们算一下时间复杂度。这个时间复杂度,应该等于(lfloor frac ki floor)有多少个不同的取值是一样的。当(i leq sqrt k)时,i只有(sqrt k)中取值,所以(lfloor frac ki floor)也最多只有(sqrt k)种取值。当(i > sqrt k)时,(lfloor frac ki floor < sqrt k),所以(lfloor frac ki floor)也最多只有(sqrt k)种取值,所以(lfloor frac ki floor)一共最多(2 sqrt k)种取值。所以该算法的之间复杂度为(O(sqrt k))

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    
    int n,k;ll ans;
    
    int main(){
    	scanf("%d%d",&n,&k);ans=1ll*n*k;
    	for(register int i=1,g;i<=n;i=g+1){
    		if(k/i!=0)g=min(n,k/(k/i));else g=n;//错误笔记:如果k/i==0即k<i的话,k/(k/i)会炸掉,所以要特判一下。 
    		ans-=(ll)(k/i)*(i+g)*(g-i+1)/2;
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    CornerNet 算法笔记
    弱监督学习下商品识别:CVPR 2018细粒度识别挑战赛获胜方案简介
    弱监督学习总结(1)
    【机器学习】模型融合方法概述
    目标检测评价标准
    目标检测Anchor-free分支:基于关键点的目标检测
    空洞卷积(dilated convolution)
    【Android】Android程序保护与破解浅析
    【随笔】入世
    【Android】Android部分问题记录
  • 原文地址:https://www.cnblogs.com/hankeke/p/CQOI2007-sum.html
Copyright © 2011-2022 走看看