欧拉函数系列
题意:
- 给定两个数 a , m ( m > a ) a, m(m>a) a,m(m>a), 求 [ 0 , m − 1 ] [0, m-1] [0,m−1]中有多少个整数使得 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 < m ≤ 1 0 10 1\leq a<m\leq 10^{10} 1≤a<m≤1010
Tutorial:
根据gcd的性质有 g c d ( a , b ) = g c d ( a % b , b ) gcd(a, b) = gcd(a\%b, b) gcd(a,b)=gcd(a%b,b), 于是乎 g c d ( a , m ) = g c d ( a + x , m ) = g c d ( ( a + x ) % m , m ) gcd(a, m) = gcd(a+x, m)=gcd((a+x)\%m, m) gcd(a,m)=gcd(a+x,m)=gcd((a+x)%m,m), 然后结合 x x x的范围观察 ( a + x ) % m (a+x)\%m (a+x)%m, 发现或者就是m的一个轮回, 相当于直接找到 g c d ( a , m ) = g c d ( x , m ) gcd(a, m) = gcd(x, m) gcd(a,m)=gcd(x,m)的x的个数,然后 0 ≤ x < m 0\leq x<m 0≤x<m,发现答案等于 Φ ( m g c d ( a , m ) ) \Phi(\frac{m}{gcd(a, m)}) Φ(gcd(a,m)m)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<ll, ll>
const ll mod = 1e9 + 7;
const ll maxn = 1e5 + 5;
ll euler(ll n)
{
ll ret = n;
for (ll i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
ret = ret / i * (i - 1);
while (n % i == 0)
n /= i;
}
}
if (n > 1)
ret = ret / n * (n - 1);
return ret;
}
ll E[maxn];
void euler()
{
for (int i = 2; i < maxn; i++)
{
if (!E[i])
for (int j = i; j < maxn; j += i)
{
if (!E[j])
E[j] = j;
E[j] = E[j] / i * (i - 1);
}
}
}
signed main()
{
int t;
cin >> t;
_rep(cas, 1, t)
{
ll a, m;
cin >> a >> m;
ll g = __gcd(a, m);
cout << euler(m/g) << endl;
}
}