bzoj2818

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.

Input

一个整数N

Output

如题

Sample Input

4

Sample Output

4

HINT

hint

对于样例(2,2),(2,4),(3,3),(4,2)


1<=N<=10^7

这题看上去一点思路都没有,但是如果我们从枚举质数角度来考虑,那么就是求gcd(i,j)=p的对数(1<=i<=n,1<=j<=n),那么我们完全可以把n/p,然后就gcd(i,j)=1的对数,对于每个p,答案极为mu(k)*[n/k]^2,由于n/k只有根号n种取值,所以对于每个p可以用根号n的时间求出对应的答案,那么枚举p的效率是n/ln(n),那么这样的复杂度就是n^1.5/ln(n),然后我们发现n/p的数的种类是根号级别的所以这题复杂度就是O(n)。


#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 10000005;
int mu[MAXN], prim[MAXN / 10], cnt;
bool f[MAXN];
int i, n, m, j, k, l;
long long ans;
inline long long getans(int n)
{
	long long tot = 0;
	for(int i = 1; i <= n;)
	{
		int j = n / i;
		int y = n / j, x = i;
		if (x > y) swap(x, y);
		tot += (mu[y] - mu[x - 1]) * j * (long long)j;
		i = y + 1;
	}
	return tot;
}
int main()
{
	mu[1] = 1;
	cin >> n;
	for(i = 2; i <= n; i ++)
	{
		if (!f[i])
		{
			prim[++cnt] = i;
			mu[i] = -1;
		}
		for(j = 1; j <= cnt && prim[j] * i <= n; j ++)
		{
			f[i * prim[j]] = 1;
			if (i % prim[j]) mu[i * prim[j]] = -mu[i];
			else {mu[i * prim[j]] = 0; break;}
		}
	}
	for(i = 2; i <= n; i ++)
		mu[i] += mu[i - 1];
	int p = 1;
	for(i = 1; i <= cnt; i ++)
	{
		if (i != cnt && n / prim[i] == n / prim[i + 1]) p ++;
		else ans += p * getans(n / prim[i]), p = 1;
	}
	cout << ans << endl;
}


你可能感兴趣的:(数论少许知识)