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