zoukankan      html  css  js  c++  java
  • 欧拉函数

    POJ 2407 Relatives

     裸题。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 2010
    15 
    16 int fat[mnx];
    17 int main(){
    18     LL n;
    19     while( scanf( "%I64d", &n ) != EOF && n ){
    20         int cnt = 0;
    21         double m = n;
    22         for( LL i = 2; i * i <= n; ++i ){
    23             if( n % i == 0 ){
    24                 fat[cnt++] = i;
    25                 while( n % i == 0 )
    26                     n /= i;
    27             }
    28             if( n == 1 ) break;
    29         }
    30         if( n != 1 ) fat[cnt++] = n;
    31         for( int i = 0; i < cnt; ++i )
    32             m *= ( 1.0 - ( 1.0 / fat[i] ) );
    33         printf( "%I64d
    ", (LL)(m+eps) );
    34     }
    35     return 0;
    36 }
    View Code

    POJ 1284  Primitive Roots

    题意:

    就是给出一个奇素数,求出他的原根的个数。

    定义:n的原根x满足条件0<x<n,并且有集合{ (xi mod n) | 1 <= i <=n-1 } 和集合{ 1, ..., n-1 }相等

    定理:如果p有原根,则它恰有φ(φ(p))个不同的原根,p为素数,当然φ(p)=p-1,因此就有φ(p-1)个原根。。

    具体看 这里

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 2010
    15 
    16 int fat[mnx];
    17 int main(){
    18     LL n;
    19     while( scanf( "%I64d", &n ) != EOF && n ){
    20         int cnt = 0;
    21         n--;
    22         double m = n;
    23         for( LL i = 2; i * i <= n; ++i ){
    24             if( n % i == 0 ){
    25                 fat[cnt++] = i;
    26                 while( n % i == 0 )
    27                     n /= i;
    28             }
    29             if( n == 1 ) break;
    30         }
    31         if( n != 1 ) fat[cnt++] = n;
    32         for( int i = 0; i < cnt; ++i )
    33             m *= ( 1.0 - ( 1.0 / fat[i] ) );
    34         printf( "%I64d
    ", (LL)(m+eps) );
    35     }
    36     return 0;
    37 }
    View Code

    POJ 2478 Farey Sequence

    欧拉函数求和。用了一个线性求欧拉函数的模板。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 1000100
    15 
    16 int pri[mnx], tot;
    17 LL phi[mnx];
    18 bool isnot[mnx];
    19 void init(){
    20     phi[1] = 1;
    21     for( int i = 2; i < mnx; ++i ){
    22         if( !isnot[i] ){
    23             phi[i] = i - 1;
    24             pri[tot++] = i;
    25         }
    26         for( int j = 0; j < tot && i * pri[j] < mnx; ++j ){
    27             isnot[i*pri[j]] = 1;
    28             if( i % pri[j] == 0 ){
    29                 phi[i*pri[j]] = phi[i] * pri[j];
    30                 break;
    31             }
    32             else phi[i*pri[j]] = phi[i] * ( pri[j] - 1 );
    33         }
    34     }
    35 }
    36 int main(){
    37     init();
    38     for( int i = 3; i < mnx; ++i ){
    39         phi[i] += phi[i-1];
    40     }
    41     int n;
    42     while( scanf( "%d", &n ) != EOF && n ){
    43         printf( "%I64d
    ", phi[n] );
    44     }
    45     return 0;
    46 }
    View Code

    POJ 3090 Visible Lattice Points

    从( 0, 0 )看,问右上角在( n, n )的正方形内,能够看到多少个点。就是( x, y ), x与y互质的点都能看到。就是欧拉函数求和 sum, sum*2 + 3就是答案了( 0, 0 ), ( 1, 0 ), ( 0, 1 )三个点也要算上。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 2010
    15 
    16 LL euler( LL x ){
    17     double ret = x;
    18     for( LL i = 2; i * i <= x; ++i ){
    19         if( x % i == 0 )
    20             ret *= ( i - 1.0 ) / i;
    21         while( x % i == 0 )
    22             x /= i;
    23     }
    24     if( x > 1 ) ret *= ( x - 1.0 ) / x;
    25     return (LL)( ret + eps );
    26 }
    27 int main(){
    28     LL n;
    29     int cas, kk = 1;
    30     scanf( "%d", &cas );
    31     while( cas-- ){
    32         scanf( "%I64d", &n );
    33         printf( "%d %I64d ", kk++, n );
    34         LL ans = 0;
    35         for( int i = 2; i <= n; ++i )
    36             ans += euler( (LL)i );
    37         printf( "%I64d
    ", ans * 2 + 3 );
    38     }
    39     return 0;
    40 }
    View Code

    POJ 3696 The Luckiest number

    题意:给你一个数L,让你求出最小的一个数能被L整除,这个数满足每一位都是8,问这个数最少有多少位。

    首先设这个有k位,则这个数可以表示为 8 / 9 * ( 10^k - 1 )   = L * m

    -> 8 * ( 10^k - 1 ) = 9 * L * m;

    设 d = gcd( 9L, 8 ) -> 8 / gcd( 9L, 8 ) * ( 10^k - 1 ) = 9 * L / gcd( 9L, 8 ) * m;

    因为 8/gcd(9L,8) 与 9L/gcd(9L,8) 互质,则等式成立的话, (10^k-1) % ( 9L/gcd(9L,8) ) == 0;

    gcd(9L, 8) = gcd(L, 8)。即 ( 10^k ) % ( 9L/gcd(L,8) ) == 1。。设 q = 9L/gcd(L,8)。。

    由欧拉定理,当gcd(10,q) == 1,k = phi(q)是其中一个解。要求最小解,就要枚举phi(q)的所有因子,看是否满足 10^k % ( phi(q)的因子 ) == 1,取最小的那个。

    若gcd( 10, q ) != 1,很明显方程无解。用了快速幂和二进制乘法( 因为有可能爆longlong)

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 100100
    15 
    16 LL gcd( LL a, LL b ){
    17     return b == 0 ? a : gcd( b, a % b );
    18 }
    19 LL phi( LL x ){
    20     double ret = x;
    21     for( LL i = 2; i * i <= x; ++i ){
    22         if( x % i == 0 )
    23             ret *= ( i - 1.0 ) / i;
    24         while( x % i == 0 )
    25             x /= i;
    26     }
    27     if( x > 1 ) ret *= ( x - 1.0 ) / x;
    28     return (LL)( ret + eps );
    29 }
    30 LL m, L;
    31 LL mul( LL a, LL b ){
    32     LL ret = 0;
    33     while( b ){
    34         if( b & 1 ) ret = ( ret + a ) % m;
    35         a = ( a + a ) % m;
    36         b >>= 1;
    37     }
    38     return ret;
    39 }
    40 int qpow( LL k ){
    41     LL ret = 1, x = 10;
    42     while( k ){
    43         if( k & 1 ) ret = mul( ret, x ) % m;
    44         x = mul( x, x ) % m;
    45         k >>= 1;
    46     }
    47     return ret == 1 ? 1 : 0;
    48 }
    49 int main(){
    50     int kk = 1;
    51     while( scanf( "%I64d", &L ) != EOF && L ){
    52         m = 9 * L / gcd( L, 8 );
    53         LL sum = phi( m ), ans = 1e15;
    54         //cout << sum << endl;
    55         if( gcd( 10, m ) != 1 ){
    56             printf( "Case %d: 0
    ", kk++ ); continue;
    57         }
    58         for( LL i = 1; i * i <= sum; ++i ){
    59             if( sum % i == 0 ){
    60                 if( qpow( i ) )
    61                     ans = min( ans, i );
    62                 if( qpow( sum / i) )
    63                     ans = min( ans, sum/i );
    64             }
    65         }
    66         printf( "Case %d: %I64d
    ", kk++, ans );
    67     }
    68     return 0;
    69 }
    View Code

     POJ 3358 Period of an Infinite Binary Expansion

    输入一个<1的分数,问你将这个小于1的小数转化为二进制形式,求最小循环部分的起始位置以及最小的循环长度。

    观察 1/10 这组。按照二进制转换法,得到 1/10, 2/10, 4/10, 8/10, 16/10, 32/10。。

    对每个分子 %10, 就可以得到 1/10, 2/10, 4/10, 8/10, 6/10, 2/10。。出现了重复,这个重复就是最小的循环长度。

    对于输入的分子pp,分母qq,首先 p = pp / gcd( pp, qq ), q = qq / gcd( pp, qq )。则 p * 2^i = p * 2^j mod q 就得到

    p * 2^i * ( 2^(j-i) - 1 ) = 0 ( mod q ); 因为gcd( p, q ) == 1,所以 q | 2^i * ( 2^(j-i) - 1 );

    因为 2^(j-i) - 1是奇数,所以 q 里面有多少个 2的幂,i 就是多少。i就是循环开始位置的前一个位置。令q'为q除去2的幂之后的数,则

    q' | 2^(j-i) - 1。。也就是求出 2^x == 1 ( mod q' ); 因为gcd( 2, q' ) == 1,所以phi( q' ) 是其中一个解。就像上一题一样找最小解就好了。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<vector>
     7 #include<queue>
     8 
     9 using namespace std;
    10 
    11 #define inf 1e16
    12 #define eps 1e-6
    13 #define LL long long
    14 #define ULL unsigned long long
    15 #define MP make_pair
    16 #define pb push_back
    17 #define mnx 1220
    18 
    19 LL gcd( LL a, LL b ){
    20     return b == 0 ? a : gcd( b, a % b );
    21 }
    22 LL phi( LL x ){
    23     double ret = x;
    24     for( LL i = 2; i * i <= x; ++i ){
    25         if( x % i == 0 )
    26             ret *= ( i - 1.0 ) / i;
    27         while( x % i == 0 )
    28             x /= i;
    29     }
    30     if( x > 1 ) ret *= ( x - 1.0 ) / x;
    31     return (LL)( ret + eps );
    32 }
    33 LL a, b;
    34 LL mul( LL x, LL y ){
    35     LL ret = 0;
    36     while( y ){
    37         if( y & 1 ) ret = ( ret + x ) % b;
    38         x = ( x + x ) % b;
    39         y >>= 1;
    40     }
    41     return ret;
    42 }
    43 int qpow( LL k ){
    44     LL ret = 1, x = 2;
    45     while( k ){
    46         if( k & 1 ) ret = mul( ret, x );
    47         x = mul( x, x );
    48         k >>= 1;
    49     }
    50     return ret == 1 ? 1 : 0;
    51 }
    52 int main(){
    53     int kk = 1;
    54     while( scanf( "%I64d/%I64d", &a, &b ) != EOF ){
    55         if( a == 0 ){
    56             printf( "Case #%d: 1,1
    ", kk++ ); continue ;
    57         }
    58         LL d = gcd( a, b );
    59         a /= d, b /= d;
    60         LL ans1 = 1, ans2 = inf;
    61         while( b % 2 == 0 ){
    62             b /= 2;
    63             ans1++;
    64         }
    65         LL s = phi( b );
    66         for( LL i = 1; i * i <= s; ++i ){
    67             if( s % i == 0 ){
    68                 if( qpow( i ) )
    69                     ans2 = min( ans2, i );
    70                 if( qpow( s/i ) )
    71                     ans2 = min( ans2, s/i );
    72             }
    73         }
    74         printf( "Case #%d: %I64d,%I64d
    ", kk++, ans1, ans2 );
    75     }
    76     return 0;
    77 }
    View Code
  • 相关阅读:
    学习笔记:@RequestMapping
    学习笔记:serializable接口实现Java对象序列化
    学习笔记:JWT在spring中的时间
    学习笔记:JWT学习
    《OpenGL编程指南》学习进度备忘
    【练习7.4】使用直方图陆地移动距离EMD区分不同光线条件下的图片cvCalcEMD2
    【练习7.3】从直方图创建signature、计算两个直方图的EMD距离
    自动变量和开辟内存的生存期和作用域探讨
    【练习7.2】直方图归一化cvNormalizeHist、匹配cvCompareHist及各种匹配方法
    【练习7.1】cvCreateHist创建直方图、cvCalcHist计算直方图、cvQueryHistValue_1D访问直方图及右左法则
  • 原文地址:https://www.cnblogs.com/LJ-blog/p/4352334.html
Copyright © 2011-2022 走看看