给定两个数a和m,在 [ 0 , m ) [0,m) [0,m)内寻找有多少个x使 g c d ( a , m ) = g c d ( a + x , m ) gcd(a,m)=gcd(a+x,m) gcd(a,m)=gcd(a+x,m)
1<=a
询问了队友后得到了正确的建模思路。。。
可以先把问题简化,通过gcd(a,m)化简一波: g c d ( a / g c d ( a , m ) , m / g c d ( a , m ) ) = 1 gcd(a/gcd(a,m),m/gcd(a,m))=1 gcd(a/gcd(a,m),m/gcd(a,m))=1
为表达简单,使 a = a / g c d ( a , m ) , m = m / g c d ( a , m ) a=a/gcd(a,m),m=m/gcd(a,m) a=a/gcd(a,m),m=m/gcd(a,m)
注意到此时问题变成了一个互质问题
在 [ 0 , m ) [0,m) [0,m)内寻找有多少个x使 1 = g c d ( a + x , m ) 1=gcd( a + x, m) 1=gcd(a+x,m)
(x的范围可能缩小了,但是删去的部分肯定不是答案,因为那部分x包含原来的a和m的公因子,不能使 g c d ( a + x , m ) = 1 gcd(a+x,m)=1 gcd(a+x,m)=1)
联想到欧几里得算法,可以将后面的部分化到最简:当a+x大于等于m时, g c d ( a + x , m ) = g c d ( ( a + x ) − m , m ) gcd(a+x,m)=gcd((a+x)-m,m) gcd(a+x,m)=gcd((a+x)−m,m)
分类:
a+x
a+x>=m时, g c d ( a + x , m ) = g c d ( a + x − m , m ) gcd(a+x,m)=gcd(a+x-m,m) gcd(a+x,m)=gcd(a+x−m,m),其中 a + x − m ∈ [ 0 , a ) a+x-m∈[0,a) a+x−m∈[0,a)
由此,问题变成求 [ 0 , m ) [0,m) [0,m)内与m互质数的个数,即欧拉函数φ(m)
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
ll gcd(ll a, ll b)
{
if (b == 0)return a;
return gcd(b, a % b);
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
ll a, m,fai=1,g;
for (int o = 0; o < t; o++)
{
cin >> a >> m;
g = gcd(a, m);
m /= g;
//求m/gcd(a,m)的欧拉函数
fai = m;
for (ll i = 2; i*i <= m; i++)
{
if (m % i == 0) {
fai = fai / i * (i - 1);
while (m % i == 0)m /= i;
}
}
if (m > 1)fai = fai / m * (m - 1);
cout << fai << endl;
}
return 0;
}