描述 Description
克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。
奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?
输入格式 Input Format
第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=10^6 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
输出格式 Output Format
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。
样例输入 Sample Input
3
1 3 4
2 7 3
3 2 1
样例输出 Sample Output
6
时间限制 Time Limitation
1s
注释 Hint
1s
来源 Source
noi 2002 day2
思路:
这道题其实和那个青蛙约会很像的哇,这道题的野人也就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<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct shadow { int c,p,l; }s[1000]; int x,y; int gcd(int a,int b) {return b==0?a:gcd(b,a%b);} void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1; y=0; return; } exgcd(b,a%b,x,y); int t=x; x=y; y=t-a/b*y; } int n; bool work(int m) { int a,b,c,t,x,y; for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { a=s[i].p-s[j].p; c=s[j].c-s[i].c; b=m; t=gcd(a,b); if(c%t==0) { a/=t;b/=t;c/=t; exgcd(a,b,x,y); b=abs(b); x=((c*x)%b+b)%b; if(!x) x+=b; if(x<=min(s[i].l,s[j].l)) return 0; } } } return 1; } int main() { cin>>n; int maxx=0; for(int i=1;i<=n;i++) { cin>>s[i].c>>s[i].p>>s[i].l; maxx=max(maxx,s[i].c); } for(int i=maxx;;i++) if(work(i)) { cout<<i<<endl; return 0; } return 0; }