【BZOJ1257】余数之和sum,数论练习之取值讨论

来源:互联网 发布:软件资格 编辑:程序博客网 时间:2024/06/10 03:11

传送门
写在前面:之前学长讲过的题目,但我硬是蛋疼了一个小时多
思路:50分随便暴力,100分看到10^9范围的数论题,应该就有两种较为常见的方法应对
1.存在某种特定的关系,甚至可以在O(1)的时间内搞出来
2.存在一些相同情况,最终可优化为√n或log级别
(不管怎么样,我们可以打表找一下规律什么的,没准就有灵感了)
这道题就是求Σ(kk/ii)i=1..n简化一下是nkΣ(k/ii)i=1..n,显然我们可以发现⌊k/i⌋的取值是一个不上升序列,且有很多取值相同(事实上,⌊k/i⌋的取值只有√k个),那么我们就可以对i中的一段区间求和(这段区间内⌊k/i⌋取值相同),⌊k/i⌋相同且i单调增加1,可以直接算出来,时间复杂度O(√k)
注意:
1.至于实现方法,我确实想了很久,最后想出来一种可能比较奇怪的转移,代码中l>r,且l为一段⌊k/i⌋取值相同的区间中最右端的数,r为最左端的数,p是这一段区间中⌊k/i⌋的取值,最后就莫名其妙地搞出来了
2.循环中注意l始终不能为0,不然将除0报错

#include<bits/stdc++.h>#define LL long longusing namespace std;LL n,k,p,l,r,ans;main(){    scanf("%lld%lld",&n,&k);    l=n;p=k/n;    while (l)    {        r=k/(p+1)+1;        ans+=(l+r)*(l-r+1)/2*p;        l=r-1;        if (!l) break;         p=k/l;    }    printf("%lld",k*n-ans);}
0 0
原创粉丝点击