GCD[caioj1280 莫反]

版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89682024

欢迎大家访问我的老师的OJ———caioj.cn

前情提要

建议先去看看Zap,数据加强了,但思路较为简单。

题面描述

传送门

思路

与Zap不同的就是多了

注意:2,3和3,2是一种情况

那么我们就要去重了。

D ( a , b , k ) D(a,b,k) 表示满足 x a , y b x\le a,y\le b k gcd ( x , y ) k \mid \gcd(x,y) 的二元组有多少对。

由于 D ( a , b , k ) = a / k b / k D(a,b,k)=\left\lfloor a/k\right\rfloor* \left\lfloor b/k\right\rfloor

F ( a , b ) F(a,b) 表示满足 x a , y b x\le a,y\le b 并且 x , y x,y 互质的二元组有多少对。

由于

F ( a , b ) = i = 1 min ( a , b ) μ ( i ) D ( a , b , i ) F(a,b)=\sum_{i=1}^{\operatorname{min}(a,b)}\mu(i)*D(a,b,i)

通过交换,我们可以得到 a = min ( a , b ) , b = max ( a , b ) a=\operatorname{min}(a,b),b=\operatorname{max}(a,b) ,因为 F ( a , b ) F(a,b) 中, x [ 2 , a ] \forall x\in[2,a] i [ 1 , x ] \forall i[1,x] ,且 i i x x 互质, i i 都被选了两次(仅在 [ 1 , a ] [1,a] 这个范围中能够互相交换,,可以画图细细感受),对于每个 x x ,根据欧拉函数的定义,这样的 i i 都有 φ ( x ) \varphi(x) 个。

所以我们要完成去重的话,我们要在Zap原答案上减去 x = 1 a φ ( x ) \large\sum_{x=1}^{a}\varphi(x)

特别地,这道题的伪欧拉 φ ( 1 ) = 0 \varphi(1)=0 ,因为 D ( 1 , 1 , 1 ) = 1 D(1,1,1)=1

分块求解即可。

就为此题答案。

AC code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
#define gc getchar()
using namespace std;
inline void qr(int &x)
{
	x=0;int f=1;char c=gc;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
	x*=f;
}
void qw(ll x)
{
	if(x/10)qw(x/10);
	putchar(x%10+48);
}
const int N=1e4+10;
const int inf=1e4;
const int M=1500;
int prime[M],miu[N],m,phi[N];bool v[N];
inline void g_p()
{
	m=0;memset(v,false,sizeof(v));miu[1]=1;phi[1]=1;
	for(int i=2;i<=inf;i++)
	{
		if(!v[i])prime[++m]=i,miu[i]=-1,phi[i]=i-1;
		for(int j=1;j<=m&&i*prime[j]<=inf;j++)
		{
			v[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				miu[i*prime[j]]=0;
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else miu[i*prime[j]]=-miu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}
inline void gcd_miu()
{
	int a,b,k;qr(a),qr(a),qr(b),qr(b),qr(k);
	a/=k,b/=k;if(a>b)swap(a,b);ll ans=0;
	for(int x=1,gx;x<=a;x=gx+1)
	{
		gx=min(a/(a/x),b/(b/x));
		ans+=(ll)(miu[gx]-miu[x-1])*(a/x)*(b/x);
	}
	ans-=phi[a];
	qw(ans);puts("");
}
void solve()
{
	for(int i=2;i<=inf;i++)miu[i]+=miu[i-1];
	for(int i=3;i<=inf;i++)phi[i]+=phi[i-1];
	int t;qr(t);while(t--)gcd_miu();
}
int main()
{
	g_p();
	solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/89682024