BZOJ1407:[NOI2002]Savage(exgcd)

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

Sample Output

6
//该样例对应于题目描述中的例子。

Solution

这不是我qbxt的时候秒了正解结果以为复杂度不对没敢讲的题么
我们发现m的最大值很小,所以我们可以枚举m,然后n个野人两两判断
怎么判断呢?$c[i]+x*p[i] equiv c[j]+x*p[j];(mod;m)$

exgcd求解即可。
如果解小于max(l[i],l[j]),那么这两个野人有生之年可以相遇

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (1000000+1000)
 5 using namespace std;
 6 
 7 int c[N],p[N],l[N],maxnum,n,x,y;
 8 
 9 int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
10 void exgcd(int a,int b,int &x,int &y)
11 {
12     if (!b){x=1; y=0; return;}
13     exgcd(b,a%b,y,x); y-=x*(a/b);
14 }
15 
16 bool check(int m)
17 {
18     for (int i=1; i<=n-1; ++i)
19         for (int j=i+1; j<=n; ++j)
20         {
21             int A=p[i]-p[j], B=m, C=c[j]-c[i];
22             int g=gcd(A,B);
23             
24             if (C%g) continue;
25             A/=g; B/=g; C/=g;//不保证A,B互质 
26             exgcd(A,B,x,y);
27             
28             if (B<0) B=-B;
29             x*=C; x=(x%B+B)%B;
30             if (x<=min(l[i],l[j])) return false;
31         }
32     return true;
33 }
34 
35 int main()
36 {
37     scanf("%d",&n);
38     for (int i=1; i<=n; ++i)
39     {
40         scanf("%d%d%d",&c[i],&p[i],&l[i]);
41         maxnum=max(maxnum,c[i]);
42         c[i]--;
43     }
44     for (int i=maxnum; i<=1000000; ++i)
45         if (check(i))
46         {
47             printf("%d",i);
48             return 0;
49         }
50 }
原文地址:https://www.cnblogs.com/refun/p/9228057.html