人生第一次作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; }