UVa 11317 GCD+LCM 欧拉函数log求位数

来源:互联网 发布:mac word 繁简转换 编辑:程序博客网 时间:2024/06/04 01:28

题意:

有如下定义:


给你一个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      : JayYeCreated Time: 2013-9-25 19:26:52File 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;}