题意:
有如下定义:
给你一个N,求G和L各自在10^100进制下的位数。
解题思路:
以前听别人说起过这题,当时还以为是很难的题,现在看看貌似挺简单的。。
一看到求位数,很容易想到用log函数求~
首先讲下求位数,x十进制的位数 = (int)log10(x) + 1,同理求x的10^100进制的位数就是把下标变成10^100即可。
设f(n) = gcd(1, n)*gcd(2, n)*gcd(3, n)...*gcd(n-1, n),则G(n) = f(1)*f(2)*..*f(n)。
对于f(n),gcd(i, n)只可能是n的因子,gcd(i, n) = d的个数为phi(n/i),这个应该很好想的。所以f(n)可以写成
写成这样的形式的话利用对数求G的位数就很简单,求L的位数也差不多,L = i*j/gcd(i,j) (1 <= i < n, i < j <= n),
由于gcd(i , j)就是前面算出的答案,只需要O(n)枚举下i (1 <= i <= n)就行。
/* **********************************************
Author : JayYe
Created Time: 2013-9-25 19:26:52
File Name : JayYe.cpp
*********************************************** */
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000000 + 10;
int phi[maxn];
double s[maxn];
// 预处理出欧拉函数
void phi_table(int n) {
phi[1] = 1;
for(int i = 2;i <= n; i++) if(!phi[i]) {
for(int j = i;j <= n;j += i) {
if(!phi[j]) phi[j] = j;
phi[j] -= phi[j]/i;
}
}
}
void init(int n) {
for(int i = 1;i <= n; i++)
for(int j = i*2;j <= n;j += i) {
s[j] += phi[j/i]*log(i);
}
for(int i = 1;i <= n; i++) s[i] += s[i-1];
for(int i = 1;i <= n; i++) s[i] /= log(10);
}
int main() {
phi_table(1000000);
init(1000000);
int n, cas = 1;
while(scanf("%d", &n) != -1 && n) {
// L 的 位数
ll ans1 = (ll)(s[n]/100) + 1;
double tmp = 0;
// 每个数在lcm相乘中都是用到n-1个
for(int i = 1;i <= n; i++) tmp += (n-1)*log(i);
tmp /= log(10);
tmp -= s[n]; // 相除即是对数相减
ll ans2 = (ll)(tmp/100) + 1;
printf("Case %d: %lld %lld\n", cas++, ans1, ans2);
}
return 0;
}