Description
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
4
Sample Output
4
Hint
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
这个题目可以用欧拉函数或者莫比乌斯反演。
第一种欧拉函数:
因为gcd(x, y) = p,所以gcd(x/p, y/p) = 1。
不妨设y较大,那么就是求所有比y/p小的数k,phi(k)的和。phi(k)是欧拉函数,表示小于等于k,与k互质的数的个数。
然后每种乘2就得到了组数,但是需要减1,因为(1, 1)这组被计算了两次。
预处理所有phi(k)的前缀和就OK了,就能加速运算。
然后枚举质数p就OK了。
这个OJ我揣测是单组测试的,像下面预处理打表会T,需要对每个n进行一次打表。
代码:(欧拉函数)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <set> #include <map> #include <queue> #include <string> #include <algorithm> #define LL long long using namespace std; const int maxN = 1e7+5; int n; bool isprim[maxN]; int phi[maxN], prim[maxN], top; LL s[maxN]; //埃氏筛法求素数 void isPrim() { top = 0; memset(isprim, true, sizeof(isprim)); isprim[0] = isprim[1] = false;//初始化 for (LL i = 2; i < maxN; ++i)//筛法 { if (isprim[i]) { for (LL j = i*i; j < maxN; j += i)//上界太大可能会爆int { isprim[j] = false; } prim[top++] = i; } } } //***筛法求欧拉函数 void phi_table() { memset(phi, 0, sizeof(phi)); phi[1] = 1; s[0] = 0; s[1] = 1; for (int i = 2; i < maxN; i++) { if (!phi[i]) for (LL j = i; j < maxN; j += i)//i如果太大可能会爆int { if (!phi[j]) phi[j] = j; phi[j] = phi[j]/i*(i-1); } s[i] = s[i-1]+phi[i]; } } void work() { LL ans = 0; for (int i = 0; i < top && prim[i] <= n; ++i) { ans += 2*s[n/prim[i]]; ans--; } printf("%lld\n", ans); } int main() { //freopen("test.in", "r", stdin); isPrim(); phi_table(); while (scanf("%d", &n) != EOF) { work(); } return 0; }