NOI 2002 荒岛野人

人生第一次作NOI的题祭!!!html

大概是NOI最简单的一道题ios

克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,之后每一年,第i个野人会沿顺时针向前走Pi个洞住下来。c++

每一个野人i有一个寿命值Li,即生存的年数。git

下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的状况。三个野人初始的洞穴编号依次为1,2,3;每一年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。spa

(图片就不考了)code

 

咱们发现这道题奇怪的给了答案的数据规模,这就说明咱们能够枚举答案。htm

而后咱们发现n的数据规模很小,n^2*m彷佛能够过。blog

咱们对于每个答案,枚举任意两我的是否不会相遇。图片

对于每两个野人,咱们能够根据他们的C和P列出同余方程:get

Ci+Pi*x≡Cj+Pj*x(mod b)  其中x是年数,b是枚举的答案。

而后,将这个同余方程转化为不定方程,而后求解。

Ci+Pi*x=Cj+Pj*x+b*-y(-y是一个构造的新的未知数)

(Pi-Pj)*x+b*y=Cj-Ci

而后用拓展欧几里得求解(这是解析)求解

最后必定要注意!!!(由于在这里卡了几个小时)求完特解之后,要保证最终解为正。

一般状况,只须要(x*(Cj-Ci)/d(最小公约数)+b/d)%b/d就能够了。

可是注意Cj-Ci可能为负,并且c++的负数取模的机制是取决于被模数,被模数为正则余数为正,为负则反之。

而由于Cj-Ci可能为负,可能致使最终答案依然为负。

故此,咱们将x*(Cj-Ci)/d先模b/d,保证其绝对值是小于b/d的,可是,b/d也可能为负(由于d可能为负),因此即便加上一个b/d也不能保证结果为正。

所以,咱们把最后加上的b/d变成一个它的倍数且保证它为正的,能够替换为b或者b/d的绝对值。

代码以下:

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAXN 10010
#define in(a) a=read()
#define REP(i,k,n)  for(int i=k;i<=n;i++)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m;
int c[100010],p[100010],l[100010];
int t;
inline void exgcd(int a,int b,int &d,int &x,int &y){
    if(b==0)  x=1,y=0,d=a;
    else  exgcd(b,a%b,d,x,y),t=x,x=y,y=t-a/b*y;
}
inline bool check(int k){
    REP(i,1,n)
        REP(j,i+1,n){
            int a=p[i]-p[j],b=k,x,y,d;
            exgcd(a,b,d,x,y);
            if((c[j]-c[i])%d!=0)  continue;
            x=((x*(c[j]-c[i])/d)%(b/d)+(abs(b/d)))%(b/d);//保证x为正
            if(x<=min(l[i],l[j]))  return 0;
        }
    return 1;
}
int main(){
    in(n);
    REP(i,1,n)  in(c[i]),in(p[i]),in(l[i]),m=max(m,c[i]);
    REP(i,m,1000000) if(check(i)){ cout<<i<<endl;  return 0;}
    return 0;
}
相关文章
相关标签/搜索