BZOJ1407: [Noi2002]Savage exgcd

Description

Input

第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
(1<=Ci,Pi<=100, 0<=Li<=10^6 )

Output

仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。

Sample Input

3
1 3 4
2 7 3
3 2 1

Sample Output

6
//该样例对应于题目描述中的例子。

Solution

对我来说很清奇的一个思路:枚举答案。我自己推了一下式子可以推出来exgcd,但是就是想不到枚举那个m,还是要多读题..

式子其实不难推

求对于最小的m ,满足

$$c_1+(p_1*x)\space mod\space m = c_2 + (p_2*x)\space mod \space m $$

的同时,满足$x>min(l_1,l_2)$

上式可化为:

$$p_1*x\space mod\space m -p_2*x\space mod\space m=c2-c1 $$

$$x*(p_1-p_2)-ym=c2-c1$$

对于x,满足$x>min(l1,l2)$

所以就化为了exgcd的标准形式,记得把x弄成最小整数解就好。

#include <bits/stdc++.h>

#define ll long long
#define inf 0x3f3f3f3f
#define il inline

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('\n')

    #define I_int int
    inline I_int read() {
        I_int x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        if( x == 0 ) { putchar( '0' ) ; return ; }
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
    }
    #undef I_int

}
using namespace io ;

#define N 100010

int n , mod , c[N] , p[N] , l[N] ;

int x , y ;
int exgcd(int a , int b) {
    if(b == 0) {x = 1 , y = 0 ; return a;}
    int ans = exgcd(b , a % b), tmp = x ;
    x = y; y = tmp - (a / b) * y;
    return ans ;
}

int main() {
    int mx = 0 ; n = read() ;
    for(int i = 1; i <= n; i ++) {
        c[i] = read() , p[i] = read() , l[i] = read() ;
        mx = std::max(mx , c[i]) ;
    } mod = mx - 1 ;
    while(1) {
        mod ++ ;
        int flag = 0;
        for(int i = 1 ; i <= n ; i ++) {
            for(int j = i + 1 ; j <= n ; j ++) {
                x = 0 , y = 0 ;
                int k = ((p[i] - p[j]) % mod + mod) % mod , tmp = c[j] - c[i] ;
                int gcd = exgcd(k , mod);
                if(tmp % gcd) continue ;
                int t = mod ;
                x *= tmp / gcd ; t /= gcd ; t = std::abs(t) ;
                x = ((x % t) + t) % t; 
                if(x <= std::min(l[i] , l[j])) {flag = 1 ; break ;}
            }
            if(flag) break ;
        }
        if(!flag) { outn(mod) ; return 0 ; }
    }
}

猜你喜欢

转载自www.cnblogs.com/henry-1202/p/10067603.html