http://acm.fzu.edu.cn/problem.php?pid=1017
題意:
給你一個K,要你求一個n, k使得k個n組成的數正好能被K整除,要求首先考慮最小的n,然後考慮最短的k。
思路:
這個題和HDU_2462相似。首先我們可以這樣考慮,對於一個由k個n組成的數字,我們不能直接去枚舉n和k,那樣顯然會超時(因爲有可能存在不存在n和k的情況),這樣我們就設法去把這樣的n,k表示成另外一種形式,這樣是一定能表示的,因爲n,k就可以唯一確定一個數,nn...nn = (99..99) / 9 * n = (10^k
- 1) /9*n ,化簡到這裏我們就可以直接求了,下面就是過程的推導:
(10^k - 1 ) / 9 * n = 0( mod K ) ----> (10^k - 1)*n = 0( mod (9*K) ) ,爲了設法將n從左邊除掉,我們可以這樣化簡 ------->
(10^k - 1) = 0 ( mod ( 9*K/gcd(9*K , n) ) ) , 依據是 ac = bc( mod p ) 化簡成a = b ( mod p ) 的條件是 gcd( c , p ) = 0。
到了這裏之後,基本的思路就出來了,我們另 p = 9 * K / gcd( 9*K , n ) , 上式就變成了:(10^k - 1) = 0 ( mod p ) ---->10^k = 1( mod p )
到這裏之後,學過歐拉定理的同學一定就可以看出來了,a^phi(p) = 1 ( mod p ) 當gcd(a, p) = 1 時成立。 這樣我們就可以先判斷gcd(10 , p )是否等於1 ,如果gcd(10 , p) != 1 ,那麼方程一定無解;否則phi(p) 一定是方程的一個解,但是並不一定是最小的解,所以我們還要將p分解質因數然後再判斷每個約數是否滿足條件即可。
還有一個沒有證明的問題就是10^k = 1 ( mod p )當gcd(10 , p)!=1時無解,這個結論可以這樣來證明:我們令x = 10 ^ (k-1) , 則上式就可以變成:10*x = 1 ( mod p ),如果解出了x,那麼k也就解出來了,上述那個方程有解的條件就是 gcd(10 , p ) == 1 , 所以得證。
代碼:
#include <stdio.h>
#include <string.h>
typedef long long LL ;
int K ;
const int PP = 110 ;
int prime[PP] , cnt ;
bool is_p[PP] ;
int fac[20] , num[20] , fnum ;
int ans , p ;
void make_prime(){
for(int i=1;i<PP;i++) is_p[i] = 1 ;
cnt = 0 ;
for(int i=2;i<PP;i++){
if( is_p[i] ){
prime[ cnt++ ] = i ;
for(int j=2;j*i<PP;j++) is_p[i*j] = 0 ;
}
}
}
int gcd(int a, int b){
while( b ){
int c = a ;
a = b ;
b = c % b ;
}
return a ;
}
void get_fac(int n){
fnum = 0 ;
for(int i=0;i<cnt && prime[i]*prime[i]<=n;i++){
if( n%prime[i] == 0 ){
int c = 0 ;
while( n%prime[i] == 0){
c ++ ; n/=prime[i] ;
}
fac[ fnum ] = prime[i] ; num[ fnum++ ] = c ;
}
}
if( n > 1 ) fac[ fnum ] = n , num[ fnum++ ] = 1 ;
}
int pmod(int a, int b, int p){
int res = 1 % p , add = a % p ;
while( b ){
if( b&1 ) res = res * add % p ;
add = add * add % p ;
b >>= 1 ;
}
return res ;
}
void dfs(int pos , int res ){
if( pos == fnum ){
if( pmod(10 , res , p) == 1 ) {
ans = ans < res ? ans : res ;
}
return ;
}
dfs( pos+1 , res) ;
int rr = res ;
for(int i=1;i<=num[ pos ] ;i++){
rr = rr * fac[ pos ] ;
dfs(pos+1 , rr) ;
}
}
int get_phi(int n){
int res = n ;
for(int i=0;i<cnt && prime[i]*prime[i]<=n ;i++){
if( n%prime[i] == 0 ){
res = res / prime[i] * ( prime[i] - 1 ) ;
while( n%prime[i] == 0 ) n /= prime[i] ;
}
}
if( n > 1 ) res = res / n * (n - 1) ;
return res ;
}
int check( int n ){
p = 9 * K / gcd( 9*K , n ) ;
// p = K / gcd(9*K , n) * 9 ;
if( gcd(10, p) != 1) return -1 ;
int ph = get_phi( p ) ;
get_fac( ph ) ;
ans = ph ;
dfs(0 , 1) ;
return ans ;
}
int main(){
make_prime() ;
while( scanf("%d",&K) == 1 ){
bool ok = 0 ;
for(int i=1;i<=9;i++){
int res = check( i ) ;
if( res == -1 ) continue ;
ok = 1 ;
printf("%d %d\n",i , res); break ;
}
if( !ok ) printf("-1\n");
}
return 0 ;
}