初始狀態為分數形式)小數點進制轉換原理:n / m ;
n /= gcd( n , m ) ;
m/= gcd( n , m ) ;
n = n % m ;
for( i : 0 to .....)
n *= k ;
bit[ i ] = n / m;(保留每一位的數值)
n %= m ;
題意:求n/m的小數點位的循環數列的長度和起始位置;
現在假設起始循環的第i個數為n,記作ni ;那麼第j個數n,則是nj;這時循環數列出現,那麼循環數列的長度為 L = j - i .
又根據小數點進制的計算原理,那麼就有nj = ( ni * 2 ^ L ) % m ;————>2 ^ L % m == 1 % m ;(求t是利用這裡求的)
當 m 與 2 互質時,根據歐拉定理,則有2^ phi( m ) == 1 %m ,因為2^ 0 == 1 , 所以起始點為0 ;也就是題目的1;
當二者不互質時,那麼m % 2 != 0 ;
因此對等式進行化簡 ,兩邊同時除以2的冪次(使得m與2互質,直到滿足歐拉函數的條件),那麼就有2^( L - t ) == 1 % ( m / ( 2 ^ t );可知,此時循環數列的起點為 t ,也就是題目的t+1;
最後我們要求的就是2^ L' = 1 % M' ;由於2^ k == 1 % m ',當k % m == 0 時取得有效值,因此,從小到大枚舉phi(m')的因子,可得到最大值
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<bitset> #include<iomanip> using namespace std; int t, n, m, GCD, phi, ans1, ans2; int temp, num; int fac[1000000]; int gcd( int a , int b ) { return b == 0 ? a : gcd( b , a % b ); } int euler(int n) { int ret=1,i; for (i=2;i*i<=n;i++) if (n%i==0) { n/=i,ret*=i-1; while (n%i==0) n/=i,ret*=i; } if (n>1) ret*=n-1; return ret; } int Pow( int a , int b , int c ) { int ans = 1 ; while( b > 0 ) { if( b & 1 ) { ans = ( long long ) ans * a % c ; } b >>= 1 ; a = ( long long )a * a % c ; } return ans ; } int main() { int Case = 1 ; while( scanf( "%d/%d" , &n , &m ) != EOF ) { GCD = gcd( n , m ) ; n /= GCD ; m /= GCD ; t = 0 ; while( m % 2 == 0 ) { t++ ; m /= 2 ; } ans1 = t + 1 ; phi = euler( m ) ; if( phi == 1 ) { ans2 = 1 ; } else { int num = 0 ; for( int i = 1 ; i * i <= phi ; ++i ) { if( phi % i == 0 ) { fac[ num++ ] = i ; fac[ num++ ] = phi / i ; } } sort( fac , fac + num ) ; for( int i = 0 ; i < num ; ++i ) { temp = Pow( 2 , fac[ i ] , m ) ; if( temp == 1 ) { ans2 = fac[ i ] ; break ; } } } printf( "Case #%d: %d,%d\n" , Case++ , ans1 , ans2 ) ; } return 0 ; } #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<bitset> #include<iomanip> using namespace std; int t, n, m, GCD, phi, ans1, ans2; int temp, num; int fac[1000000]; int gcd( int a , int b ) { return b == 0 ? a : gcd( b , a % b ); } int euler(int n) { int ret=1,i; for (i=2;i*i<=n;i++) if (n%i==0) { n/=i,ret*=i-1; while (n%i==0) n/=i,ret*=i; } if (n>1) ret*=n-1; return ret; } int Pow( int a , int b , int c ) { int ans = 1 ; while( b > 0 ) { if( b & 1 ) { ans = ( long long ) ans * a % c ; } b >>= 1 ; a = ( long long )a * a % c ; } return ans ; } int main() { int Case = 1 ; while( scanf( "%d/%d" , &n , &m ) != EOF ) { GCD = gcd( n , m ) ; n /= GCD ; m /= GCD ; t = 0 ; while( m % 2 == 0 ) { t++ ; m /= 2 ; } ans1 = t + 1 ; phi = euler( m ) ; if( phi == 1 ) { ans2 = 1 ; } else { int num = 0 ; for( int i = 1 ; i * i <= phi ; ++i ) { if( phi % i == 0 ) { fac[ num++ ] = i ; fac[ num++ ] = phi / i ; } } sort( fac , fac + num ) ; for( int i = 0 ; i < num ; ++i ) { temp = Pow( 2 , fac[ i ] , m ) ; if( temp == 1 ) { ans2 = fac[ i ] ; break ; } } } printf( "Case #%d: %d,%d\n" , Case++ , ans1 , ans2 ) ; } return 0 ; }