链接:http://codeforces.com/gym/101334/attachments
题目大意:
求解 ∑ i = 1 n ( k m o d i ) \sum_{i=1}^n{(k \ mod \ i)} ∑i=1n(k mod i)
分析:
可以通过找规律得出来或者数学方面
以K=29为例,i从1到29.
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
29%i | 0 | 1 | 2 | 1 | 4 | 5 | 1 | 5 | 2 | 9 | 7 | 5 | 3 | 1 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
可以发现像9,7,5,3,1这段是以等差数列出现的,这段的起始的是余9的10,可以通过29/3+1得到,尾是余1的14,可以通过29/2,可以发现等差数列的两端除的数都是与相邻数,其实可以将其分成两部分:①1到sqrt(k),②sqrt(k)+1到n,而第二部分里的几个等差数列的始末位置,可以通过K/前一部分的数得来。那么因此在计算的时候可以i从1遍历到sqrt(k),然后再比较n的大小,若在此等差数列内,就利用等差数列求和公式;n>k的部分直接加上k*(n-k)。
具体看代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod =10001;
int main()
{
// 下面这两个一定要加上
freopen("joseph.in","r",stdin);
freopen("joseph.out","w",stdout);
ll n, k;
while(~scanf("%lld%lld",&n,&k))
{
int tem=sqrt(k+0.5);
ll ans=0;
if(n<=tem)
{
for(int i=1;i<=n;i++)
{
ans+=k%i;
}
}
else // n>tem
{
for(int i=1;i<=tem;i++)
{
ans+=k%i;
if(n>=k/i&&i!=k/i)
{
ans+=( (k%( k/i)+k%( k/(i+1)+1))*(k/i-k/(i+1))/2 );
}
else if(n<k/i&&n>=k/(i+1)+1)
{
ans+=( (k%( n)+k%( k/(i+1)+1))*(n-k/(i+1))/2 );
}
// cout<<"i="<<i<<",ans="<<ans<<endl;
}
}
if(n>k)
{
ans+=k*(n-k);
}
printf("%lld\n",ans);
}
return 0;
}