荒岛野人

来源:互联网 发布:网络协议由什么组成 编辑:程序博客网 时间:2024/04/29 13:28

Description

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

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

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。

分析

对于一个合法的m,必须满足的是n个人两两之间必须不能走重合。现在的问题是如何判定了。对于每两个人我们都可以算出他们走到同一个点的最短时间。
列出式子就是:ci+pi*x=cj+pj*x(mod m),再转化:(pi-pj)*x-my=cj-ci
那么我们已知pi-pj,m,cj-ci现在要求的是x。
这样就有了ax+by=c。这样一个式子已经很接近同余方程了,但不是。
同余方程是ax+by=gcd(a,b)。对此若上面的方程有解那么必有c%gcd(a,b)=0
这样可以转化成a’x+b’y=c’而a’=a/gcd(a,b),b’,c’类似。
此时再转化:a’x’+b’y’=1.那么求出x’后x=x’*c/gcd(a,b)。然而这里求出的x,y只是一组可行解,并不是最小解。
这里有:
a(x-b)+b(y+a)=gcd(a,b)
a(x-2b)+b(y+2a)=gcd(a,b)
。。。。。
a(x+2b)+b(y-2a)=gcd(a,b)
……..
所以我们只需把x%b’,就可以得到x>0且x最接近0的解了。(注意这里是b’)

找出了x的时候,再判断一下x是否<=min(l[i],l[j]),若是的话m便不合法,否则反之。

最后注明一下这里的每个式子转化时除的数必须是可以整除,所以我们才类似的用a/gcd(a,b)

var    n,i,k,j,ma,a,b,d,x,y,cc:longint;    c,p,l:array[1..15] of longint;    bz:boolean;function max(l,r:longint):longint;begin    if l<r then exit(r) else exit(l);end;function exgcd(a,b:longint;var x,y:longint):longint;var t,er:longint;begin    if b=0 then begin       x:=1;y:=0;exit(a);    end else begin       er:=exgcd(b,a mod b,x,y);       t:=x;       x:=y;       y:=t-(a div b)*y;       exit(er);    end;end;function min(l,r:longint):longint;begin    if l<r then exit(l) else exit(r);end;begin    readln(n);    for i:=1 to n do begin        readln(c[i],p[i],l[i]);        ma:=max(ma,c[i]);    end;    for k:=ma to 1000000 do begin        bz:=true;        for i:=1 to n-1 do begin           for j:=i+1 to n do begin               a:=p[i]-p[j];b:=k;cc:=c[j]-c[i];               if (k=6)and(i=2) then                 n:=n;               d:=exgcd(a,b,x,y);               if cc mod d<>0 then continue;               x:=(x*cc div d) mod (b div d);               if x<0 then x:=x+abs(b div d);               if x<=min(l[i],l[j]) then begin                  bz:=false;break;               end;           end;        if not bz then break;        end;        if bz then break;    end;    writeln(k);close(input);close(output);end.
0 0