luogu2257 YY的GCD

题目链接

problem

给出一个(n,m(n,mle 10^7)),求(sumlimits_{i=1}^nsumlimits_{j=1}^mgcd(i,j)in P)
P表示全部素数的集合。
(T,(Tle 10000))组询问

solution

枚举因数

[原式=sumlimits_{din P} sumlimits_{i=1}^{frac{n}{d}}sumlimits_{j=1}^{frac{m}{d}}epsilon(gcd(i,j)=1) ]

因为(epsilon=1*mu)

[所以上式=sumlimits_{din P} sumlimits_{i=1}^{frac{n}{d}}sumlimits_{j=1}^{frac{m}{d}}sumlimits_{k|i,k|j}mu(k)\ =sumlimits_{din P}sumlimits_{k=1}^{frac{min(n,m)}{d}}mu(k)lfloorfrac{n}{dk} floorlfloorfrac{m}{dk} floor ]

(t=dk)

原式=$$sumlimits_{t=1}^{min(n,m)}lfloorfrac{n}{t} floor lfloorfrac{m}{t} floorsumlimits_{din P,d|t}mu(frac{t}{d})$$

发现前面这一块数论分块就好了,后面就提前预处理出来,求个前缀和。

预处理复杂度(O(nloglogn)),单次询问复杂度(O(sqrt{n}))

code

	/*
	* @Author: wxyww
	* @Date:   2020-01-20 19:08:26
	* @Last Modified time: 2020-01-20 19:18:39
	*/
	#include<cstdio>
	#include<iostream>
	#include<cstdlib>
	#include<cstring>
	#include<algorithm>
	#include<queue>
	#include<vector>
	#include<ctime>
	using namespace std;
	typedef long long ll;
	const int N = 10000010;
	ll read() {
		ll x=0,f=1;char c=getchar();
		while(c<'0'||c>'9') {
			if(c=='-') f=-1;
			c=getchar();
		}
		while(c>='0'&&c<='9') {
			x=x*10+c-'0';
			c=getchar();
		}
		return x*f;
	}
	int mu[N],pri[N],tot,vis[N];
	void pre() {
		mu[1] = 1;
		for(int i = 2;i < N;++i) {
			if(!vis[i]) pri[++tot] = i,mu[i] = -1;
			for(int j = 1;j <= tot && 1ll * i * pri[j] < N;++j) {
				vis[i * pri[j]] = 1;
				if(i % pri[j]) mu[i * pri[j]] = -mu[i];
				else {
					mu[i * pri[j]] = 0;break;
				}
			}
		}
	}
	int f[N];
	int main() {
		pre();

		for(int i = 1;i <= tot;++i) {
			int js = 1;
			for(int k = pri[i];k < N;k += pri[i],++js) {
				f[k] += mu[js];
			}
		}

		for(int i = 1;i < N;++i) f[i] += f[i - 1];

		int T = read();
		while(T--) {
			int n = read(),m = read();
			ll ans = 0;
			for(int l = 1,r;l <= min(n,m);l = r + 1) {
				r = min(n / (n / l),m / (m / l));
				ans += 1ll * (n / l) * (m / l) * (f[r] - f[l - 1]);
			}
			printf("%lld
",ans);
		}
		return 0;
	}
原文地址:https://www.cnblogs.com/wxyww/p/luogu2257.html