Problem:给定,求
。
标签:高中数学题(一元一次不等式+等差数列求和)
首先我们考虑:当时,
。对于这部分单独处理即可。
现在我们考虑的情况(
时显然答案是0)
对于被除数和除数
,
。我们现在考虑的就是如何快速累加
。
显然,假定不随
的变化而变化时,
每
,
。反之,
每
,
。
所以,在某个特定的范围内(前提是
不变)变换时,
在这些取值下的出
可以通过求等差数列(公差为
)的方法求出。
举个例子:
当时:当除数(模数)取
,商均为1,余数就是
,是一个公差为1的等差数列。
问题来了:如何求出上面说的的“特定范围”?
让我们先看之前那个式子:
假设是确定的,我们根据
的定义,可知:
又由,得:
现在我们再确定的上界:当以上式子
中
取
时,有:
在式子
中,
也就是说:我们可以通过枚举,从而求出对应模数
的范围,在此时求出来的模数
的范围内,余数
的变化规律呈等差数列分布。这样我们便可以利用等差数列通项公式来
求了。
Code:
#include<cstdio>
#include<iostream>
using namespace std;
long long n,k,xj,fst,lst,tot,minn,ans;
int main()
{
scanf("%lld%lld",&k,&n);
if(n<=k)
{
ans=(k-n)*n;
k=n-1;
}
xj=n/k;
for(long long a=xj;a<=n;a++)
{
minn=(n+1)/(a+1);
if(k<=100000) break;
//当k取到10万左右时,x的值域涵盖的整数就很少了,这时直接暴力累加答案即可。
if((n+1)%(a+1)>0) minn+=1;
fst=n%k,lst=n%minn;
tot=(lst-fst)/a+1;
ans+=tot*fst+a*tot*(tot-1)/2;
k=minn-1;
}
for(long long i=1;i<=k;i++) ans+=n%i;
cout<<ans;
return 0;
}