Savage(扩展欧几里得)

Savage

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
//该样例对应于题目描述中的例子。

题解:
由于洞穴是环状的,所以联想到mod。
看到答案不超过1e6,所以可以从小到大枚举ans,看看每个ans是否合法,如果合法就直接输出。
首先如果没有寿命的限制,那我们可以列出同余方程ci+pi*x≡cj+pj*x(mod ans)(1<=i,j<=n),如果合法的话,说明x是无解的。
但是题目中每个人寿命,所以要做一些改变,也就是说当ans合法的时候不仅有上面那个同余方程无解,也可以解出来的x>min(li,lj)

代码如下

#include <cstdio>
#include <algorithm>
using namespace std;
int n,c[20],p[20],l[20],ax;
void exgcd(int a,int b,int &g,int &x,int &y){
    if (!b) g=a,x=1,y=0;
    else exgcd(b,a%b,g,y,x),y-=x*(a/b);
}
bool pd(int A){
    for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++){
        int a=((p[i]-p[j])%A+A)%A,b=((c[j]-c[i])%A+A)%A,x,y,G,F;
        exgcd(a,A,G,x,y);if (b%G) continue;b/=G;F=A/G;
        x=(b*x%F+F)%F;if (x<=l[i] && x<=l[j]) return 0;
    }
    return 1;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d%d%d",&c[i],&p[i],&l[i]),ax=max(c[i],ax);
    for (int i=ax;;i++) if (pd(i)) {printf("%d
",i);return 0;}
    return 0;
}
原文地址:https://www.cnblogs.com/xjqxjq/p/10544734.html