[國家集訓隊]Crash的數字表格

Crash的數字表格

題解

很明顯的一道莫比烏斯板子題。

原式\sum_{i=1}^{n}\sum_{j=1}^{m} [i,j]\left(n \leq m \right )

=\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{(i,j)}

=\sum_{d=1}^{n}\frac{1}{d}\sum_{i=1}^{n}\sum_{j=1}^{m}ij[(i,j)==d]

=\sum_{d=1}^{n}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij[(i,j)==1]

f\left (k \right )=\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij[(i,j)==k],g\left( k\right )=\sum_{k|x}f(x)

反演可得f\left(1 \right )= \sum \mu \left(k \right )g\left(k \right )= \sum_{k=1}^{n/d}\mu\left(k \right )g\left(k \right )

可得,g\left(k \right )=\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij[k|(i,j)]

= \sum_{i=1}^{n/dk}\sum_{j=1}^{m/dk}ijk^2[gcd(i,j)]

= k^2\sum_{i=1}^{n/dk}\sum_{j=1}^{m/dk}ij

S(x)= \frac{x(x+1)}{2}

g(k)= k^2S(\left \lfloor \frac{n}{dk} \right \rfloor)S\left(\lfloor \frac{m}{dk} \rfloor \right )

ans= \sum_{d=1}^{n}d\sum_{k=1}^{n/d}\mu\left(k \right )k^2S\left(\lfloor \frac{n}{dk} \rfloor \right )S\left( \lfloor \frac{m}{dk} \rfloor \right )

= \sum_{T=1}^{n}\left(T\sum_{d|T}d \mu\left(d \right ) \right )S\left( \lfloor \frac{n}{T} \rfloor \right )S\left(\lfloor \frac{m}{T} \rfloor \right )

這樣就可以分塊計算了。

源碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 10000010
typedef long long LL;
#define int LL
const int INF=0x7f7f7f7f;
const int mo=20101009;
typedef pair<int,int> pii;
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
int mobius[MAXN],prime[MAXN],cntp;
bool oula[MAXN]; 
void init(int n){
	mobius[1]=1;
	for(int i=2;i<=n;i++){
		if(!oula[i])prime[++cntp]=i,mobius[i]=mo-i+1;
		for(int j=1;j<=cntp&&i*prime[j]<=n;j++){
			oula[i*prime[j]]=1;
			if(i%prime[j])mobius[i*prime[j]]=mobius[i]*mobius[prime[j]]%mo;
			else{mobius[i*prime[j]]=mobius[i];break;}
		}
	}
	for(int i=1;i<=n;i++)mobius[i]=mobius[i]*i%mo;
	for(int i=1;i<=n;i++)mobius[i]=(mobius[i]+mobius[i-1])%mo;
}
int S(int n){return n*(n+1)/2%mo;}
int n,m,ans; 
signed main(){
	read(n);read(m);if(n>m)swap(n,m);init(n);
	for(int l=1,r;l<=n;l=r+1){
		r=min(n/(n/l),m/(m/l));
		ans=(ans+(mobius[r]-mobius[l-1]+mo)%mo*S(n/l)%mo*S(m/l)%mo)%mo;
	}
	printf("%lld\n",ans);
	return 0;
}

謝謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章