紫書 例題 10-27 UVa 10214(尤拉函式)

Sugewud發表於2018-07-20

只看一個象限簡化問題,最後答案乘4+4

象限裡面列舉x, 在當前這條固定的平行於y軸的直線中

分成長度為x的一段段。符合題目要求的點gcd(x,y) = 1

那麼第一段1<= y <= x,個數為phi(x)個,即是x的尤拉函式值

第二段x+1 <= y <= 2x, 因為gcd(x + i, x) = gcd(x, i)

 接下來同理

一直到最後一段

kx + 1 <= y <= b要單獨一個個算,因為最後一段的長度不一定為x

感覺這道題算每一條直線時分成長度為x的一段段很巧妙,不好想到

#include<cstdio>
#include<cmath>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

typedef long long ll;

int 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;
}


int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }

ll f(int a, int b)
{
	ll ans = 0;
	REP(x, 1, a + 1)
	{
		int k = b / x;
		ans += phi(x) * k;
		REP(y, k*x + 1, b + 1)
			if(gcd(x, y) == 1)
				ans++;	
	}	
	return 4 * ans + 4;
}

int main()
{
	int a, b;
	while(~scanf("%d%d", &a, &b) && a)
	{
		ll K = f(a, b);
		ll N = (ll)(2 * a + 1) * (2 * b + 1) - 1;
		printf("%.7lf\n", (double)K / N);
	} 
	return 0;
}

 

相關文章