数论 GCD 最大公约数 欧拉函数经典题 洛谷 CF1295D Same GCDs Codeforces1295D

​前言

两个月了,我终于更了……

这两个月忙(chen)于(mi)内(xiang)卷(le),现在终于出新文章啦,(也算兑现了当初的出数论题文章的承诺~

不说废话了,今天给大家介绍一道CF/洛谷上的数论题———CF1295D Same GCDs/1295D #81 Problem D。

这是一道相当不错的题,很考验选手的思维能力以及数学基础,先贴个题面~

洛谷题目传送门 or Codeforces题目传送门​​​​​​​​​​​​​​​​​​


题目描述

You are given two integers a a a and m m m . Calculate the number of integers x x x such that 0 ≤ x < m 0≤x<m 0x<m and g c d ( a , m ) gcd(a, m) gcd(a,m) = g c d ( a + x , m ) gcd(a + x, m) gcd(a+x,m).

Note: gcd(a, b) is the greatest common divisor of a a a and b b b .

输入格式

The first line contains the single integer T T T( 1 ≤ T ≤ 50 1≤T≤50 1T50) — the number of test cases.

Next T lines contain test cases — one per line. Each line contains two integers a a a and m m m ( 1 ≤ a < m ≤ 1 0 10 1≤a<m≤10^{10} 1a<m1010) .

输出格式

Print T T T integers — one per test case. For each test case print the number of appropriate x x x -s.

题意翻译

∑ i = 1 n [ g c d ( a , m ) = g c d ( a + x , m ) ] \displaystyle\sum_{i=1}^n[ gcd(a,m)=gcd(a+x,m) ] i=1n[gcd(a,m)=gcd(a+x,m)]

多组测试数据, T ≤ 50 , 1 ≤ a < m ≤ 10 T≤50, 1≤a<m≤10 T50,1a<m10

输入输出样例

输入 #1
3
4 9
5 10
42 9999999967
输出 #1
6
1
9999999966

​说明/提示

In the first test case appropriate x x x -s are [ 0 , 1 , 3 , 4 , 6 , 7 0, 1, 3, 4, 6, 7 0,1,3,4,6,7].

In the second test case the only appropriate x x x is 0 0 0 .


解题思路

那么,看完题目,第一反应肯定是这题正解绝对不是用暴力,真要暴力的话你会在某Online Judge得到优秀的40pts
所以,我们要费点功夫,处理一下这个式子。

前置芝士 ———欧拉函数

是的,这题也绕不开欧拉,那么,什么是欧拉函数呢?
定义:在数论中,对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。
贴张书照———
出自长乐一中董永建老师团队
(出自长乐一中董永建老师团队所撰书籍《信息学奥赛一本通高效进阶》,侵删。)
那么,简单来讲,欧拉函数 φ ( n ) \varphi(n) φ(n)就表示小于 n n n又与 n n n互质的数的数量。
几个基本性质:

  1. n n n= p k p^{k} pk,其中 n , k n,k n,k为正整数, p p p为质数,则有 φ ( n ) = p k − p k − 1 \varphi(n)=p^{k}-p^{k-1} φ(n)=pkpk1
  2. n , m n,m n,m为正整数, g c d ( n , m ) gcd(n,m) gcd(n,m)=1,则有 φ ( n m ) = φ ( n ) ∗ φ ( m ) \varphi(nm)=\varphi(n)*\varphi(m) φ(nm)=φ(n)φ(m)

如何计算 φ ( n ) \varphi(n) φ(n)呢?请看: φ ( n ) = n ∗ ∑ i = 1 n ( 1 − 1 p i ) \varphi(n)=n*\displaystyle\sum_{i=1}^n(1-\frac{1}{p_i}) φ(n)=ni=1n(1pi1)
用代码实现即为:

long long ans=n;
for (int i=2;i<=sqrt(n);i++) {//寻找因数
   	if (n%i==0) n/=i,ans=ans/i*(i-1);//这里做去分母处理,否则会因精度问题WA
    while (n%i==0) n/=i;//除尽此因数
	if (n>1) {//计算时有可能会出现一个未除的m的质因子,出现m>1 ,说明还剩一个质因子没除
		ans=ans/n*(n-1);
	}
	cout << ans << endl;	
}

现在,切入正题~

当然,只有欧拉函数是不足以解这题的,还要用到关于 g c d gcd gcd的两个定理:

  1. ∀ n , m ∈ N , m ≤ n , g c d ( n , m ) = g c d ( m , n − m ) = g c d ( n , n − m ) ( 更相减损术 ) \forall n,m \in \Nu,m≤n,gcd(n,m)=gcd(m,n-m)=gcd(n,n-m)(更相减损术) n,mN,mn,gcd(n,m)=gcd(m,nm)=gcd(n,nm)(更相减损术)
  2. ∀ n , m ∈ N \forall n,m \in \Nu n,mN,设 g c d ( n , m ) = k gcd(n,m)=k gcd(n,m)=k g c d gcd gcd ( n k \frac{n}{k} kn, m k \frac{m}{k} km) = = = 1 1 1

开始推导:
设 g c d ( a , m ) = g c d ( a + x , m ) = k 设gcd(a,m)=gcd(a+x,m)=k gcd(a,m)=gcd(a+x,m)=k
则 g c d ( a + x k , m k ) = 1 则gcd( \frac{a+x}{k},\frac{m}{k})=1 gcd(ka+x,km)=1
分以下两种情况讨论: 分以下两种情况讨论: 分以下两种情况讨论:
1. 当 a + x k < m k 时 : 1.当\frac{a+x}{k}<\frac{m}{k}时: 1.ka+x<km:
则求 [ a k , m k ) 这个区间内与 m k 互质的数 则求[\frac{a}{k},\frac{m}{k})这个区间内与\frac{m}{k}互质的数 则求[ka,km)这个区间内与km互质的数
2. 当 a + x k > m k 时 : 2.当\frac{a+x}{k}>\frac{m}{k}时: 2.ka+x>km:
∵ g c d ( a + x k , m k ) = 1 \because gcd( \frac{a+x}{k},\frac{m}{k})=1 gcd(ka+x,km)=1
∴ g c d ( a + x − m k , m k ) = 1 \therefore gcd( \frac{a+x-m}{k},\frac{m}{k})=1 gcd(ka+xm,km)=1
则求 [ 0 , a k ) 这个区间内与 m k 互质的数 则求[0,\frac{a}{k})这个区间内与\frac{m}{k}互质的数 则求[0,ka)这个区间内与km互质的数
结合以上两种情况知:即求 [ 0 , m k ) 这个区间内与 m k 互质的数 结合以上两种情况知:即求[0,\frac{m}{k})这个区间内与\frac{m}{k}互质的数 结合以上两种情况知:即求[0,km)这个区间内与km互质的数
即求 φ ( m k ) 即求\varphi(\frac{m}{k}) 即求φ(km)
推导完毕 推导完毕 推导完毕
现在,我们通过式子变形,明确了我们解决该题的方法。那么,问题就很简单了。这道看似无从下手的题,转化成了求一个欧拉函数的问题。
好了,上代码,解释都在代码里:

#include <bits/stdc++.h>
using namespace std;
int t;
long long a, m;
int main() {
    cin >> t;
    while (t--) {
        scanf("%lld%lld",&a,&m);
        long long k = __gcd(a, m);//gcd函数
        m/=k;//除去最大公约数
        long long ans=m;//记得开long long
		for (int i=2;i<=sqrt(m);i++) {//欧拉函数模板
   			if (m%i==0) m/=i,ans=ans/i*(i-1);
        	while (m%i==0) m/=i;
		}
		if (m>1) {
			ans=ans/m*(m-1);
		}
		cout << ans << endl;	
    }
    return 0;
}

完结撒花……(等我先总个结)


总结

说实话,我在模拟赛做这题时,真的很懵,后来也是推导了很久才想出正解(蒻)。这题考验选手的知识储备,思维能力以及熟练运用知识的能力,对码力要求其实并不高,是一道数论好题。这题也可以用其他方法解,比如莫比乌斯反演,在我接下来的文章可能也会提到。最后,祝大家(当然也包括本蒟蒻)CSP RP++!
(再等等)
大家觉得CSP各题会出什么样的算法呢?(求各路大佬为本蒟蒻指点迷津qwq)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值