【问题描述】

克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞 C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个 山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。

[NOI2002] 荒岛野人   扩展欧几里得算法 [NOI2002] 荒岛野人   扩展欧几里得算法

[NOI2002] 荒岛野人   扩展欧几里得算法 [NOI2002] 荒岛野人   扩展欧几里得算法

奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?


【输入文件】

输入文件的第1行为一个整数N(1<=N<=15),即野人的数目。第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=106 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。


【输出文件】

输出文件仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6

solution

(其实这个题根据 M不大于10^6 知道要枚举M)


我一开始思路是:

设当前总共的洞穴数是m个

对于每两个野人,如果他们会相遇,那么会有

(C[i]+k*P[i])≡(C[j]+k*P[j]) (%m)

即 m*t1=C[i]+k*P[i]...①  m*t2=C[j]+k*P[j]...②

①+②得   m*(t1+t2)-(P[i]+P[j])*k=C[i]+C[j]

可是这样没法解方程,就放弃了

 


 

看题解是:

对于野人i   (C[i]+k*P[i])%m=S1→C[i]+k*P[i]-k1*m=S1

对于野人j   (C[j]+k*P[j])%m=S2→C[j]+k*P[j]-k2*m=S2

相遇的条件是 S1==S2

所以两式相减  (P[i]-P[j])*k+x*m=C[j]-C[i]   (此时野人相遇S1==S2)

最后如果方程 无解 OR k>L[i]||k>L[j]  即为不相遇

 

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cstdlib>
 5 #define ll long long
 6 #define dd double
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 using namespace std;
 9 inline int maxn(int a,int b){return a>b?a:b;}
10 int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
11 
12 int n,be;
13 int C[21],p[21],L[21];
14 
15 void egcd(int a,int b,int &x,int &y)
16 {
17     if(b==0)
18     {
19         x=1;
20         y=0;
21         return ;
22     }
23     egcd(b,a%b,x,y);
24     int temp=x;
25     x=y;
26     y=temp-a/b*y;
27 }
28 
29 int check(int now)
30 {
31     int x,y,d,a,b,c;
32     for(int i=1;i<=n;++i)
33       for(int j=i+1;j<=n;++j)
34       {
35             a=p[i]-p[j];
36             b=now;
37             c=C[j]-C[i];
38             d=gcd(a,b);
39             
40             if(c%d!=0)
41               continue;
42             a/=d;
43             b/=d;
44             c/=d;
45             egcd(a,b,x,y);
46             b=abs(b);
47             x=((x*c)%b+b)%b;
48             if(x==0)
49               x+=b;
50             if(x<=min(L[i],L[j]))
51               return 0;
52         }
53     return 1;
54 }
55 
56 int main(){
57     
58     //freopen("savage.in","r",stdin);
59     //freopen("savage.out","w",stdout);
60     
61     //freopen("1.txt","r",stdin);
62     
63     scanf("%d",&n);
64     for(int i=1;i<=n;++i)
65     {
66       scanf("%d%d%d",&C[i],&p[i],&L[i]);
67         be=maxn(be,C[i]);
68     }
69     for(int i=be;i<=1000000;++i)
70       if(check(i))
71       {
72             cout<<i;
73             break;
74         }
75     //while(1);
76     return 0;
77 }
code

相关文章: