CodeVS1747_NOI2002_荒岛野人_Savage_C++
题目:http://codevs.cn/problem/1747/
对于一个环,我们经常用取余来表示它走过若干圈后的位置
那么第 i 个野人第 x 年时所在的位置可表示为:(c[i]+p[i]*x)%m (若结果为 0 则变为 m)
若两个野人不产生冲突,则在它们俩最小的寿命之内,每一年的位置都会不同
可列出不等式,对于第 i 和第 j 号野人,(c[i]+p[i]*x)%m!=(c[j]+p[j]*x)%m
但是不等式十分不好解,则把它转化为等式,并做变换
(c[i]+p[i]*x)%m=(c[j]+p[j]*x)%m
c[i]+p[i]*x+my1=c[j]+p[j]*x+my2
p[i]*x-p[j]*x+my1-my2=c[j]-c[i]
(p[i]-p[j])*x+m(y1-y2)=c[j]-c[i]
其中 y1 与 y2 取多少我们不关心,因为它只是一个走多少圈的问题,把它合为 y
再设 a=p[i]-p[j] , b=m , c=c[j]-c[i]
方程化为 ax+by=c
这就是一个解不等式的问题,用 exgcd 求
(exgcd 扩展欧几里德算法详解:
http://www.cnblogs.com/hadilo/p/5914302.html)
要求无解(不会遇上)或者得到的最小解大于 min(l[i],l[j]) (在寿命短的那个野人死后才遇上)
那么枚举 m ,然后 n2 的判断是否有会遇上的情况即可
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 const int N=16; 10 int d[N],p[N],l[N],x,y,n,m; 11 inline int gcd(int a,int b) 12 { 13 return b?gcd(b,a%b):a; 14 } 15 inline void exgcd(int a,int b) 16 { 17 if (b) 18 { 19 exgcd(b,a%b); 20 int k=x; 21 x=y; 22 y=k-a/b*y; 23 } 24 else y=(x=1)-1; 25 } 26 bool check() 27 { 28 int i,j,a,b,c,r; 29 for (i=1;i<n;i++) 30 for (j=i+1;j<=n;j++) 31 { 32 a=p[i]-p[j]; 33 b=m; 34 c=d[j]-d[i]; 35 r=gcd(a,b); 36 if (c%r) continue; 37 exgcd(a,b); 38 b=abs(b/r); 39 x=(x/r*c%b+b)%b; 40 if (!x) x+=b; 41 if (x<=min(l[i],l[j])) return 1; 42 } 43 return 0; 44 } 45 int main() 46 { 47 int i,s=0; 48 scanf("%d",&n); 49 for (i=1;i<=n;i++) 50 { 51 scanf("%d%d%d",&d[i],&p[i],&l[i]); 52 s=max(d[i],s); 53 } 54 for (m=s;check();m++); 55 printf("%d\n",m); 56 return 0; 57 }
版权所有,转载请联系作者,违者必究
联系方式:http://www.cnblogs.com/hadilo/p/5932395.html