[清华集训2012]模积和(数论分块)

\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[i\ne j](n\mod i)(m\mod j)\), 对 \(19940417\) 取模(至今未考证出是什么日子)。\(1\le n,m\le 10^9\)

先来看看这个式子有什么特点,然后开拆:

  • \([i\ne j]\) 看起来需要容斥掉;
  • 取模似乎可以转化为下取整,数论分块——数据范围验证了这一点。

下面进行推导:

不妨设 \(n\le m\),原式可变形为 \(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(n\mod i)(m\mod j)-\sum\limits_{i=1}^{n}(n\mod i)(m\mod i)\);
交换求和符号顺序,有 \(\sum\limits_{i=1}^{n}(n\mod i)\sum\limits_{j=1}^{m}(m\mod j)-\sum\limits_{i=1}^{n}(n\mod i)(m\mod i)\);
将取模转换为下取整形式:\(\sum\limits_{i=1}^{n}(n-i \lfloor \frac{n}{i}\rfloor)\sum\limits_{j=1}^{m}(m-j \lfloor \frac{m}{j}\rfloor)-\sum\limits_{i=1}^{n}(n-i \lfloor \frac{n}{i}\rfloor)(m-j\lfloor \frac{m}{j}\rfloor)\);
拆开第二大项的括号,有\(\sum\limits_{i=1}^{n}(n-i \lfloor \frac{n}{i}\rfloor)\sum\limits_{j=1}^{m}(m-j \lfloor \frac{m}{j}\rfloor)-\sum\limits_{i=1}^{n}(n m-m i \lfloor \frac{n}{i}\rfloor-n i \lfloor \frac{m}{i}\rfloor+i^2\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloor)\)

不需要再拆了,这个又臭又长的式子已经可以用数论分块处理了。

有一个小问题:第二大项最后的 \(i^2\) 怎么处理?

平方和数列求和公式:\(\sum\limits_{i=1}^{n}=\frac{n(n+1)(2n+1)}{6}\)。数归显然可证。

下面是 AC 代码:

#define int long long
const int p=19940417;
int m1(int x){return (x*(x+1)>>1)%p;}//等差数列求和
int m2(int x){//平方和数列求和
	return x%3==1?(x*(x+1)>>1)%p*((x<<1|1)/3)%p:(x*(x+1)/6)%p*(x<<1|1)%p;
}
int f(int x){//数论分块,g()同
	int ans=0;
	for(int l=1,r,len;l<=x;l=r+1){
		r=x/(x/l),len=r-l+1;
		(ans+=len*x%p-(x/l)%p*(m1(r)-m1(l-1)))%=p;
	}
	return (ans+p)%p;
}
int g(int x,int y){
	int ans=0;
	for(int l=1,r,len;l<=x&&l<=y;l=r+1){
		r=min(x/(x/l),y/(y/l)),len=r-l+1;//因为有两个下取整相乘,故取min保证正确性
		(ans+=x*y%p*len)%=p;
		(ans-=(x*(y/l)+y*(x/l))%p*(m1(r)-m1(l-1)))%=p;
		(ans+=(x/l)*(y/l)%p*(m2(r)-m2(l-1)))%=p;
	}
	return (ans+p)%p;
}
signed main(){
	int n=rd(),m=rd();
	printf("%lld\n",(f(n)*f(m)%p-g(n,m)+p)%p);
	return 0;
}

THE END

posted @ 2021-10-07 20:40  q0000000  阅读(55)  评论(0编辑  收藏  举报