zoukankan      html  css  js  c++  java
  • BZOJ1257: [CQOI2007]余数之和

    这是本人第一篇博客,写的不好请尽力吐槽。
    Time Limit: 5 Sec Memory Limit: 128 MB
    Submit: 6612 Solved: 3190
    [Submit][Status][Discuss]
    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
    首先,我不知道为什么5s的时限下,暴力为什么过不了。
    然后,看书看不懂,网上的博客不清不楚。于是,我又重新看了一遍书……
    因为k mod i=kk~ mod~ i =k- kiileftlfloordfrac{k}{i} ight floor*i,所以ans=n*k-i=1nsum_{i=1}^n kiileftlfloordfrac{k}{i} ight floor *i
    对于任意xxin [1,k][1,k],设g(x)=k/kxleftlfloor k/leftlfloordfrac{k}{x} ight floor ight floor.
    因为函数f(x)=k/xf(x)=k/x(不向下取整)当xN+x in N+ 时,函数单调递减,g(x)&gt;=k/f(x)=xg(x)&gt;=leftlfloor k/f(x) ight floor=x,故k/ g(x)leftlfloor k/ g(x) ight floor<=k/x leftlfloor k/ x ight floor

    同时,k/ g(x)leftlfloor k/ g(x) ight floor>=k/(k/k/x)leftlfloor k / ( k/ leftlfloor k/x ight floor) ight floor(除数小,商就大)=k/kk/ xleftlfloor k/k* leftlfloor k / x ight floor ight floor=
    k/x leftlfloor k / x ight floor.
    所以k/ g(x)leftlfloor k/ g(x) ight floor=k/x leftlfloor k / x ight floor
    gxg(x)换元得到k/ k/kileftlfloor k/ leftlfloor k/leftlfloor dfrac{k}{i} ight floor ight floor ight floor=k/x leftlfloor k / x ight floor(好丑啊)
    又因为f(x)f(x)的性质,所以当iiin [x,k/kileftlfloor k/leftlfloordfrac{k}{i} ight floor ight floor ]时,f(i)f(i)随着ii的增大而减小(x恒大于0,反比例函数的性质),那么 f(i)leftlfloor f(i) ight floor就是非上升函数,因为两端的i f(i)i ,leftlfloor f(i) ight floor值都相等了,对于中间的i f(i)i ,leftlfloor f(i) ight floor也一定相等。
    我们就可以把1~n分成若干块,每一块的 k/ileftlfloor k/i ight floor都相等,于是就可以用等差数列求和的方法就每一块的值。时间复杂度由O(n)O(n)O(n)变为O(surd{n})
    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int main()
    {
    	ll n,k;scanf("%lld%lld",&n,&k);
    	ll ans=n*k;
    	for(int i=1,m;i<=n;i=m+1)
    	{
    		k/i?m=min(n,k/(k/i)):m=n;//分块
    		ans-=((k/i)*(i+m)*(m-i+1))/2;//等差数列求和
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    [linux] SIGPIPE信号处理
    巧妙使用spring对commons fileUpload的包装
    对commons fileupload组件的简单封装
    利用脚本启动java程序
    [linux] 创建daemon进程
    利用Jakarta commons fileupload组件实现多文件上传
    dedeCms下面 arclist标签无法嵌套图片(img)之解决办法
    编程乱码问题初步探索
    PHP下载文件函数
    Windows7下IIS中以FastCgi安装PHP
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373941.html
Copyright © 2011-2022 走看看