P2261 [CQOI2007]余数求和
解题思路:
由题意得:ans=
根据a mod b=a-b
我们可以通过式子的转移算出$$ans=nk-\sum_{i=1}^{n}i*[\frac{k}{i}]$$
我们用样例来列一个格来看看k/i的规律(见下表)
|i| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: | -----------: |
|
我们发现在某一段内一段连续的
用l来代表我们当前除法块的左边界,r来代表右边界,我们让一开始的l=1,因为第一块除法块的开头永远都是从1开始(问为什么的去重新读题),然后我们可以通过l来求出r。
t=k/l;
if (t==0) r=n;
else r=min(k/t,n);
因为我们t的定义是
当t=0时,r=n。
当t!=0时,r=min([\frac{k}{t}] ,n)
解释如下,因为当t=0时,后面那一块肯定都是大于k的那一段,所以我们直接让r=n,算出最后这一大块,当t!=0的时候,我们让r=
每一块的和 = 当前块的 t
剩下的就是用n*k减去没一块的值就好了
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
long long ans;
long long n,k;
long long min(long long x,long long y)
{
return x<y?x:y;
}
int main()
{
scanf("%lld %lld",&n,&k);
ans=n*k;
for (long long l=1,r,t;l<=n;l=r+1)//l,r就是解释里面的左右边界,t=k/i
{
t=k/l;//求出当前的t
if (t==0) r=n;//如思路的
else r=min(k/t,n);
ans-=(t*(r-l+1)*(l+r)/2);
}
printf("%lld\n",ans);
}