RUPC F, AOJ-2286: Farey Sequence

問題概要

N(<10^6)が与えられる。0以上1以下の既約な有理数で、分母がN以下であるようなものが何通りあるか求める問題。テストケース10^6くらい。

考えたこと

  • 即数列検索。
  • ヒット。何かΦ関数が見える。
  • 言われてみればそれは自明。漸化式a[1]=2, a[i] = a[i-1] + card({x in [1..i] | xとiは互いに素}) = a[i-1] + Φ(i)。
  • 後は書くだけ。無事通った。

本番で通ったコード

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long int64;
const int MAX_N = (int)(1e6);

int64 phi[MAX_N + 1];
int64 fs[MAX_N + 1];
int64 ans[MAX_N + 1];
int64 accum[MAX_N + 2];

void euler_phi(){
	for(int i=0; i<=MAX_N; i++){
		fs[i] = true;
		phi[i] = i;
	}

	for(int i=2; i<=MAX_N; i++){
		if(fs[i]){
			phi[i] -= phi[i] / i;
			for(int j=2*i; j<=MAX_N; j+=i){
				fs[j] = false;
				phi[j] -= phi[j] / i;
			}
		}
	}
}

void pre_solve(){
	euler_phi();

	for(int i=1; i<=MAX_N; i++){
		accum[i] = accum[i-1] + phi[i];
	}

	for(int i=1; i<=MAX_N; i++){
		ans[i] = 1 + accum[i+1];
	}

	ans[0] = 2;
}

int64 solve(int N){
	return ans[N - 1];
}

int main(){

	pre_solve();

	int T, N;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&N);
		printf("%lld\n", solve(N));
	}

	return 0;
}