1. 程式人生 > >BZOJ1407: [Noi2002]Savage exgcd

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