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;
}
相關文章
相關標籤/搜索