HDU2588 GCD
Problem
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.
For each test case,output the answer on a single line.
Solution
设p=(X,N) (1<=x<=n),存在a,b,使得ap=X,bp=N,易知(a,b)=1。
问题转化为对于每一个p>=M,存在多少对a,b,求总的数量。
枚举p|N(p>=M),可以得到b=N/p,由于ab互质,ab对的数量为euler(N/p)。
由于p与N/p对称,枚举根号的量即可。
代码是用的质因数分解后枚举。
Code
#include<stdio.h>
#include<set>
#include<iostream>
#include<stack>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#ifdef io_opt
#define scanf sb
#define printf sb
#endif
typedef long long ll;
typedef __int128 lll;
typedef double db;
using namespace std;
#define eps 0.000000001
const int PN = 100000;
int pn;
bool ipr[PN + 10];
int pri[PN / 5];
int phi[PN + 10];
void prime() {
memset(ipr, true, sizeof(ipr));
ipr[1] = false;
int N = sqrt(PN) + 0.5;
for (int i = 2; i <= N; i++) {
if (ipr[i]) {
int d = i == 2 ? i : 2 * i;
for (int j = i * i; j <= PN; j += d) {
ipr[j] = false;
}
}
}
for (int i = 1; i <= PN; i++) {
if (ipr[i]) pri[++pn] = i;
}
}
void eprime() { //not verify
memset(ipr, true, sizeof(ipr));
ipr[1] = false;
phi[1] = 1;
for (int i = 2; i <= PN; i++) {
if (ipr[i]) pri[++pn] = i, phi[i] = i - 1;
for (int j = 1; j <= pn && pri[j] * i <= PN; j++) {
ipr[pri[j] * i] = false;
if (i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]];
else {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
}
}
}
int euler_phi(int n) {
int ans = n;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
ll speed(ll a, ll b, ll p) {
ll cur = a, ans = 1;
while (b) {
if (b & 1) ans = ans * cur % p;
cur = cur * cur % p;
b >>= 1;
}
return ans % p;
}
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
int T, n, m, cnt, ans;
int a[100020], b[100020];
void fj(int t) {
cnt = 0;
for (int i = 1; i <= pn && pri[i] * pri[i] <= t; i++) {
if (t % pri[i] == 0) a[++cnt] = pri[i], b[cnt] = 0;
while (t % pri[i] == 0) {
b[cnt]++;
t /= pri[i];
}
}
if (t > 1) a[++cnt] = t, b[cnt] = 1;
if (cnt == 0) a[1] = 1, b[1] = 1;
}
void dfs(int t, int cur) {
if (t == cnt + 1) {
if (cur >= m) {
ans += euler_phi(n / cur);
}
return;
}
dfs(t + 1, cur);
for (int i = 1; i <= b[t]; i++) {
cur *= a[t];
dfs(t + 1, cur);
}
}
int main() {
io_opt;
eprime();
cin >> T;
while (T--) {
cin >> n >> m;
ans = 0;
fj(n);
dfs(1, 1);
cout << ans << endl;
}
return 0;
}