1. 程式人生 > 其它 >P2522 [HAOI2011]Problem b

P2522 [HAOI2011]Problem b

簡要題意

\(n\) 組資料,每組資料給定 \(a,b,c,d,k\),計算:

\[\sum_{i=a}^{b}\sum_{j=c}^{d}{[\gcd(i,j)=k]} \]

\(a\leq b,c\leq d,1\leq n,a,b,c,d,k\leq5\times10^4\)。時間限制 \(2.5\operatorname{s}\)

簡要題意

莫比烏斯反演基礎練習題。

首先容斥,令 \(f(x,y)=\sum_{i=1}^{x}\sum_{j=1}^{y}[\gcd(i,j)=k]\)。則原式化為:

\[f(b,d)-f(a-1,d)-f(b,c-1)+f(a-1,c-1) \]

考慮化簡 \(f\)

先將 \(i,j\) 同時約去 \(k\),得:

\[\sum_{i=1}^{\lfloor\frac{x}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{y}{k}\rfloor}[\gcd(i,j)=1] \]

根據莫比烏斯函式性質:\(\sum_{d\mid x}{\mu(d)}=[x=1]\) 得:

\[\sum_{i=1}^{\lfloor\frac{x}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{y}{k}\rfloor}\sum_{d\mid\gcd(i,j)}{\mu(d)} \]

將第三個 \(\sum\) 的下限變形得:

\[\sum_{i=1}^{\lfloor\frac{x}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{y}{k}\rfloor}\sum_{d\mid i,d\mid j}{\mu(d)} \]

\(d\) 提到前面去,得:

\[\sum_{d=1}^{\min(x,y)}\mu(d)\sum_{i=1}^{\lfloor\frac{x}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{y}{k}\rfloor}[d\mid i][d\mid j] \]

將右邊得兩個 \(\sum\) 化簡,得:

\[\sum_{d=1}^{\min(x,y)}\mu(d)\lfloor\frac{x}{dk}\rfloor\lfloor\frac{y}{dk}\rfloor \]

數論分塊做即可。

時間複雜度 \(O(\max(b,d)+T\sqrt{\min(b,d)})\)

注意,不要 #define int long long

程式碼

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+5;
int mu[N],prime[N],tot;
long long sum[N];
bool vis[N];
int a,b,c,d,k,t;

inline void sieve(int bound){
	mu[1]=1;vis[1]=1;
	for(int i=2;i<=bound;i++){
		if(!vis[i]){
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot&&i*prime[j]<=bound;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]) mu[i*prime[j]]=-mu[i];
			else{
				mu[i*prime[j]]=0;
				break;
			}
		}
	}
	for(int i=1;i<=bound;i++){
		sum[i]=sum[i-1]+mu[i];
	}
}

long long solve(int x,int y){
	long long ret=0;
	for(int i=1,j;i<=min(x,y);i=j+1){
		j=min(x/(x/i),y/(y/i));
		ret+=(1ll*x/(1ll*i*k))*1ll*(1ll*y/(1ll*i*k))*(sum[j]-sum[i-1]);
	}
	return ret;
}

signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	sieve(5e4);
	cin>>t;
	while(t--){
		cin>>a>>b>>c>>d>>k;
		cout<<(solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1))<<'\n';
	}
	return 0;
}