这个博客写的很详细。 http://blog.csdn.net/braketbn/article/details/50715971 看图会发现规律(图是盗的):
看了很久我才明白,mdzz。 设k = d * x + r。发现每个块内都是一个等差数列,公差就是d。 其实原理很简单, 假设x是使k/x=d的最小整数,(当然,向下取整) 写成k=d* x+r, 如果r>d,那么就会有k=d* (x+1)+r-d, 如果r>2d,那么就会有k=d* (x+2)+r-2d, 所以等差数列的第一项是k-d*x即k%x. 最后一项就应该是k-d*y即k%y。 其中y是使k/y=d的最大整数(当然,向下取整)。
因为此时k=d*y+r (r必定 < d)。 于是我们枚举d,按d分块。(这里其实是枚举等差数列的第一项,第一项确定,d也跟着确定) 对于一个块[L, R](指的是i的区间),显然R = k / d,那么d怎么求呢? (L=k/(d+1)+1,这里其实就是i) 首先i从1(第一次必定满足i是使k/x=d的最小整数)开始, d=k/i, r=(k/d) 然后i=r+1(保证下一次时i也满足i是使k/x=d的最小整数),接着代码。。。。 注意:求出来的r不能大于n
#include <stdio.h>
typedef unsigned long long ULL;
int main(
int argc,
char const *argv[])
{
ULL n,k,ans=
0;
scanf(
"%llu %llu",&n,&k);
for(ULL i=
1,r;i<=n;i=r+
1)
{
ULL d=k/i;
r=d?(k/d):n;
r=(r>n)?n:r;
ans+=(k-i*d+k-r*d)*(r-i+
1)/
2;
}
printf(
"%llu\n",ans );
return 0;
}
转载请注明原文地址: https://ju.6miu.com/read-1294999.html