【P2260 [清华集训2012]模积和】题解

题目地址

题目

\[\sum_{i=1}^{n} \sum_{j=1}^{m} (n \bmod i) \times (m \bmod j), i \neq j \]

mod 19940417 的值

image

思路

\(n\leq m\)

\[\Large\sum_{i=1}^{n} (n \bmod i) \times \sum_{j=1}^{m}(m \bmod j)-\sum_{i=1}^ n (n\bmod i)(m\bmod i) \]

前面那两坨就是个数论分块板子,后面那块拆一下:

\[\Large \sum_{i=1}^n(nm-\frac m i\times in-\frac n i \times im+\frac m i\times\frac n i\times i^2) \]

这里还是可以数论分块,每次块的 \(r\) 可以取 \(\min(\dfrac m l, \dfrac n l)\)

然后还有几个难点

  1. 后面那坨鬼东西乘 \(i^2\),众所周知二次方和公式 \(\sum_{i=1}^n i^2=\dfrac {n(n+1)(2n+1)}6\)

  2. 然后上面那个鬼公式因为上面三个乘起来会爆所以要用逆元

  3. 然后因为↑↓出题人模数不是质数不能用费马只能老老实实打拓欧

Code

// Problem: P2260 [清华集训2012]模积和
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2260
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
#define mo 19940417
//#define N
int n, m, i, j, k, T; 
int ans, l, r, P; 

int kuai(int a, int b)
{
	int ans=1; 
	while(b)
	{
		if(b&1) ans*=a; 
		a*=a; b>>=1; 
		ans%=mo; a%=mo; 
	}
	return ans; 
}

void exgcd(int a, int b, int &x, int &y)
{
	if(b==0) x=1, y=0; 
	else
	{
		exgcd(b, a%b, x, y); 
		int z=y; 
		y=x-a/b*y; 
		x=z; 
	}
}

int calc(int n)
{
	int ans=n*n%mo, l, r; 
	for(l=1; l<=n; l=r+1)
	{
		r=min(n, n/(n/l)); 
		ans-=(l+r)*(r-l+1)/2%mo*(n/l)%mo; 
		ans%=mo; 
	}
	return ans; 
}

int sim(int n)
{
	return n*(n+1)%mo*(2*n+1)%mo*P%mo; 
}

int suan(int l, int r)
{
	return (sim(r)-sim(l-1))%mo; 
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	exgcd(6, mo, P, T); 
	n=read(); m=read(); 
	if(n>m) swap(n, m); 
	ans=calc(n)*calc(m)%mo; 
	for(l=1; l<=n; l=r+1)
	{
		r=min({n, n/(n/l), m/(m/l)}); 
		ans-=(r-l+1)*n%mo*m%mo; 
		ans+=(l+r)*(r-l+1)/2%mo*n%mo*(m/l)%mo; 
		ans+=(l+r)*(r-l+1)/2%mo*m%mo*(n/l)%mo; 
		ans-=(m/l)*(n/l)%mo*suan(l, r)%mo;  
		ans=(ans%mo+mo)%mo;
	}
	printf("%lld\n", ans); 
	return 0; 
}

总结

本题考察一下知识点;

  1. 式子化简(是个人都会)
  2. 数论分块(在学,这几天做个笔记)和其拓展应用(如本题)
  3. 二次和公式(以前用过,但忘了)
  4. 拓欧求逆元(学了又忘,再学又忘,还是要靠推)
posted @ 2022-07-29 12:42  zhangtingxi  阅读(22)  评论(0编辑  收藏  举报