Calculating[LuoguP3935]

版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89680573

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思路

根据算数基本定理,正约数个数为: ( c 1 + 1 ) ( c 2 + 1 ) . . . . . . ( c m + 1 ) = i = 1 m ( c i + 1 ) (c_1+1)*(c_2+1)*......*(c_m+1)={\large\prod\limits_{i=1}^{m}}(c_i+1)

f ( i ) f(i) 实际上就是 i i 的正约数个数.

我们来变柿子:( i j = = x i*j==x 返回bool值)
  f ( x ) = d x 1 = i = 1 x j = 1 x / i ( i j = = x ) ( ) \large\ f(x)=\sum_{d\mid x}1=\sum_{i=1}^x\sum_{j=1}^{x/i}(i*j==x)(即正约数的个数)

x = 1 n f ( x ) = x = 1 n i = 1 x j = 1 x / i ( i j = = x ) \large\sum_{x=1}^nf(x)=\sum_{x=1}^n\sum_{i=1}^x\sum_{j=1}^{x/i}(i*j==x)

我们这是可以发现,对于每一个 i j i*j 都会有一个与 i j i*j 相等的 x x 与其对应,因此我们可以改变一下顺序:
x = 1 n f ( x ) = i = 1 n j = 1 n / i 1 = x = 1 n i = 1 n / x 1 = x = 1 n n / x \large\sum_{x=1}^nf(x)=\sum_{i=1}^n\sum_{j=1}^{\left\lfloor\\ n/i\right\rfloor}1=\sum_{x=1}^n\sum_{i=1}^{\left\lfloor\\ n/x\right\rfloor}1=\sum_{x=1}^n\left\lfloor\\ n/x\right\rfloor

现在我们要求的是
x = l r f ( x ) = x = 1 r f ( x ) x = 1 l 1 f ( x ) = x = 1 r r / x x = 1 l 1 ( l 1 ) / x \large\sum_{x=l}^rf(x)=\sum_{x=1}^rf(x)-\sum_{x=1}^{l-1}f(x)=\sum_{x=1}^r\left\lfloor\\ r/x\right\rfloor-\sum_{x=1}^{l-1}\left\lfloor\\ (l-1)/x\right\rfloor

e m m . . . . . . . emm.......

我们观察一下n的范围,貌似会T,分块吧

参考余数之和的证明,我们设 g ( x ) = k / k / x \operatorname{g}(x)=\left\lfloor\\ k/\left\lfloor\\k/x \right\rfloor \right\rfloor k / g ( x ) = k / x \left\lfloor k/ \operatorname{g}(x)\right\rfloor=\left\lfloor\\k/x \right\rfloor

所以我们可以直接分块啦!

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;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/89680573