版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89680573
欢迎大家访问我的老师的OJ———caioj.cn
题面描述
传送门
思路
根据算数基本定理,正约数个数为:
(c1+1)∗(c2+1)∗......∗(cm+1)=i=1∏m(ci+1)
则
f(i)实际上就是
i的正约数个数.
我们来变柿子:(
i∗j==x返回bool值)
f(x)=d∣x∑1=i=1∑xj=1∑x/i(i∗j==x)(即正约数的个数)
x=1∑nf(x)=x=1∑ni=1∑xj=1∑x/i(i∗j==x)
我们这是可以发现,对于每一个
i∗j都会有一个与
i∗j相等的
x与其对应,因此我们可以改变一下顺序:
x=1∑nf(x)=i=1∑nj=1∑⌊n/i⌋1=x=1∑ni=1∑⌊n/x⌋1=x=1∑n⌊n/x⌋
现在我们要求的是
x=l∑rf(x)=x=1∑rf(x)−x=1∑l−1f(x)=x=1∑r⌊r/x⌋−x=1∑l−1⌊(l−1)/x⌋
emm.......
我们观察一下n的范围,貌似会T,分块吧
参考余数之和的证明,我们设
g(x)=⌊k/⌊k/x⌋⌋
⌊k/g(x)⌋=⌊k/x⌋
所以我们可以直接分块啦!
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define ll long long
using namespace std;
const ll mod=998244353;
int main()
{
ll l,r;scanf("%lld%lld",&l,&r);
if(l>r)swap(l,r);
l--;
ll ans=0;
for(ll x=1,gx;x<=r;x=gx+1)
{
gx=r/(r/x);if(l>=i)gx=min(gx,l/(l/x));
ans=(ans+(gx-x+1)*(r/x-l/x))%mod;
}
if(ans<0)ans+=mod;
printf("%lld\n",ans);
return 0;
}