GCD[caioj1280 莫反]

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

前情提要

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

题面描述

传送门

思路

与Zap不同的就是多了

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

那么我们就要去重了。

D ( a , b , k ) D(a,b,k) D(a,b,k)表示满足 x ≤ a , y ≤ b x\le a,y\le b xa,yb k ∣ gcd ⁡ ( x , y ) k \mid \gcd(x,y) kgcd(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 D(a,b,k)=a/kb/k

F ( a , b ) F(a,b) F(a,b)表示满足 x ≤ a , y ≤ b x\le a,y\le b xa,yb并且 x , y 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) F(a,b)=i=1min(a,b)μ(i)D(a,b,i)

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

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

特别地,这道题的伪欧拉 φ ( 1 ) = 0 \varphi(1)=0 φ(1)=0,因为 D ( a , b , 1 ) = a ∗ b D(a,b,1)=a*b D(a,b,1)=ab仅包含一个 ( 1 , 1 , 1 ) (1,1,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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值