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 ; }