[Noi2002]Savage 题解
[Noi2002]Savage
时间限制: 5 Sec 内存限制: 64 MB题目描述
输入
第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
(1<=Ci,Pi<=100, 0<=Li<=10^6 )
输出
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。
样例输入
3
1 3 4
2 7 3
3 2 1
样例输出
6
//该样例对应于题目描述中的例子。
这道题明眼人都能看得出来是扩展欧几里得,然而怎么搞就是一个问题了,如果对扩展欧几里得不是太熟可以先做一下 青蛙的约会 裸题,但要注意一下你的模板必须正确,否则像本博主这样的蒟蒻调半天才发现模板有错就崩了。(本博主扩展欧几里得的板子来自Q某犇,据Q某犇说他也是找了好久才发现神利.代目学长写正确模板,其余好多都是错误的)
首先我们完全可以把青蛙那道题的主要代码都搬过来,由于这道题并不符合单调性,想二分的同学就扑街了,我也是其中之一。
由于n很小m最大不过1000,000我们从小到大挨个枚举就好了,时间复杂度最坏就是n^2*log(max(c[i]))*1000000,反正时间有5秒,而且这只是最坏复杂度,所以貌似是可以的。然后就简单了,两个野人相遇的条件是他们能相遇且两人都存活,因此我们只要算出他们两个相遇的时间是否比他们中寿命最短的那个长就行了。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<map> 7 #include<queue> 8 #include<string> 9 #include<cmath> 10 using namespace std; 11 int n,c[20],p[20],l[20]; 12 int exgcd(int a,int b,int &x,int &y){ 13 if(b==0) 14 { 15 x=1; 16 y=0; 17 return a; 18 } 19 int t=exgcd(b,a%b,x,y); 20 int o=x; 21 x=y; 22 y=o-a/b*y; 23 return t; 24 } 25 bool check2(int a,int b,int L){ 26 int x,y; 27 int gcd=exgcd(p[a]-p[b],L,x,y); 28 if(((c[b]-c[a])%gcd)!=0) 29 return 1; 30 int aa=p[a]-p[b],bb=L; 31 aa/=gcd,bb/=gcd; 32 exgcd(aa,bb,x,y); 33 bb=abs(bb); 34 x=x*(c[b]-c[a])/gcd; 35 x%=bb; 36 if(x<0) x+=bb; 37 if(x>min(l[a],l[b])) return 1; 38 return 0; 39 } 40 bool check1(int L){ 41 for(int i=1;i<=n;i++) 42 { 43 for(int j=i+1;j<=n;j++) 44 { 45 if(!check2(i,j,L)) 46 { 47 return 0; 48 } 49 } 50 } 51 return 1; 52 } 53 int main(){ 54 // freopen("savage.in","r",stdin); 55 // freopen("savage.out","w",stdout); 56 scanf("%d",&n); 57 int st=0; 58 for(int i=1;i<=n;i++) 59 { 60 scanf("%d%d%d",&c[i],&p[i],&l[i]); 61 st=max(st,c[i]); 62 } 63 int ans=0; 64 for(int i=st;;i++) 65 { 66 if(check1(i)) 67 { 68 ans=i; 69 break; 70 } 71 } 72 printf("%d\n",ans); 73 // while(1); 74 return 0; 75 }