[noi2002]荒岛野人
思路:
这道题其实和那个青蛙约会很像的哇,这道题的野人也就15个不直接扩展欧几里得不会超时的,因为你要让每次没有两个野人在同一个山洞里(可能是野人不喜欢一起讨论哲学♂的事吧哈哈,我们假设这一全有m个山洞,我们用结构体存一下每个野人的寿命s[i].l,每个野人的初始山洞s[i].c,每个野人每次移动山洞的个数a[i].p,所以我们可以得出一个方程s[i].c+x*s[i].p≡s[j].c+x*s[j].p(mod m)。这个方程可以化简为(s[i].p-s[j].p)*x-my=s[j].c-s[i].c;我们要时这个方程无解(这样就表示野人i他永远也追不上野人j)因为每个野人还有寿命,所以当我们求出的x>min(s[i].l,s[j].l)时这时的山洞数也当然成立,因为野人i在死后才会追上野人j,所以他俩也当然不会住在一起哲♂学了哇。。。
超时看下方↓
{这样是不是就A了呢??当然不是你会发现超时了........这是为什么呢?(我当时也是稀里糊涂的超了)
我还在纳闷怎么会超时,然后发现,当你在用扩展欧几里得的定理求a/d*x+b/d*y=c/d的时候要用到
t=gcd(a,b);又因为a=s[i].p-s[j].p;这显然可以发现野人i每次跑的距离可以比野人j的少哇,所以肯定可能
为负数...........然后你将b取个abs就好了}
代码
#include<bits/stdc++.h> using namespace std; int m,n,c[20],p[20],l[20]; int exgcd(int a,int b,int &x,int &y) { if(!b){x=1,y=0;return a;} int tmp=exgcd(b,a%b,x,y); int t=x;x=y,y=t-(a/b)*y; return tmp; } bool bol(int m) { for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { int a=p[j]-p[i],b=m,cc=c[i]-c[j],x,y; int f=exgcd(a,b,x,y); if(cc%f)continue; a/=f,b/=f,cc/=f; x=(x*cc%b+b)%b;if(x<0) x-=b; if(x<=min(l[i],l[j]))return 0; } } return 1; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>c[i]>>p[i]>>l[i],m=max(m,c[i]); while(!bol(m)) m++; cout<<m; return 0; }
愿你走出半生,归来仍是少年