题目
算法分析
有的小伙伴看到这道题,第一感觉是这样的:好简单。这么水一道题,不是有手就行? 于是码出了这样一段代码:
int n,k,ans;
int main()
{
n=readint(); k=readint();
for(rg int i=1;i<=n;++i)
{
ans+=(k%i);
}
printf("%d\n",ans);
return 0;
}
但是很抱歉的是,只能过一个点。
本题其实用到了整除分块的一些推论以及等差数列的相关知识。
- 对于 i i i属于 [ x , k / ( k / x ) ] [x,k/(k/x)] [x,k/(k/x)], k / i k/i k/i的值都相等。 例如 k = 15 , x = 9 k=15,x=9 k=15,x=9则对于 i i i属于区间 [ 9 , 15 / ( 15 / 9 ) ] [9,15/(15/9)] [9,15/(15/9)]即 [ 9 , 15 ] [9,15] [9,15], k / i k/i k/i的值都相等。
- 等差数列求和公式:(首项+末项)* 项数 /2。
在本题中 由于我们知道
k
m
o
d
i
=
k
−
k
/
i
∗
i
k\,mod\,i=k-k/i*i
kmodi=k−k/i∗i,因此结果为
k
∗
n
−
∑
i
=
1
n
k
/
i
∗
i
k*n-\sum_{i=1}^{n}k/i*i
k∗n−i=1∑nk/i∗i
具体代码如下:
Code
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rg register
#define ll long long
using namespace std;
inline int sread()
{
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
long long int n,k,ans,ans1;
int main()
{
scanf("%lld %lld",&n,&k);
ans=n*k;
int l,r;
for(rg int i=1;i<=n;i)
{
if(k>=i)
{
l=i;
r=k/(k/i);
if(r<=n) ans1+=(k/l*l+k/r*r)*(r-l+1)/2;
else if(r>n) ans1+=(k/l*l+k/n*n)*(n-l+1)/2;
i=r+1;
}
else if(k<i)
{
i++;
}
}
ans=ans-ans1;
printf("%lld\n",ans);
return 0;
}
反思与总结
1.记得该开
l
o
n
g
l
o
n
g
long\,long
longlong的时候一定要开(我在这卡了半天)。
2.要对数学的基础知识熟练掌握并能灵活运用。
3.数论相关题目需要在思考的同时大量演算。