一本通1637荒岛野人
1637:荒岛野人
Description
Input
第1行为一个整数N(1<=N<=15),即野人的数目。第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=106 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
Output
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于106。
Sample Input
3
1 3 4
2 7 3
3 2 1
1 3 4
2 7 3
3 2 1
Sample Output
6
View Code
该样例对应于题目描述中的例子。
sol:感觉挺难的,想了好久吧。。
原式:
C[i]+k*P[i] = C[j]+k*P[j] (%Mod)
使得该式的解k无解或k>min(L[i],L[j])
转化
C[i]+k*P[i] = C[j]+k*P[j] (%Mod)
k*(P[i]-P[j]) = C[j]-C[i] (%Mod)
k*(P[i]-P[j])+x*Mod = C[j]-C[i] (类ax+by=c的形式) (要求的是k和x)
然后暴力枚举答案,n2判断即可
Ps:实现的时候有个细节要注意,式子里的k不能是0,
/* 原式: C[i]+k*P[i] = C[j]+k*P[j] (%Mod) 使得该式的解k无解或k>min(L[i],L[j]) 转化 C[i]+k*P[i] = C[j]+k*P[j] (%Mod) k*(P[i]-P[j]) = C[j]-C[i] (%Mod) k*(P[i]-P[j])+x*Mod = C[j]-C[i] (类ax+by=c的形式) (要求的是k和x) */ #include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') /* k*(P[i]-P[j])+x*Mod = C[j]-C[i] */ const int N=20; int n,C[N],P[N],L[N]; inline ll gcd(ll x,ll y) { return (!y)?(x):(gcd(y,x%y)); } inline void Exgcd(ll a,ll b,ll &X,ll &Y) { if(b==0) { X=1; Y=0; return; } Exgcd(b,a%b,X,Y); ll XX=X,YY=Y; X=YY; Y=XX-a/b*YY; return; } inline bool Solve(ll Mod) { int i,j; for(i=1;i<n;i++) { for(j=i+1;j<=n;j++) { ll a=P[i]-P[j],b=Mod,c=C[j]-C[i]; ll r=gcd(a,b),X,Y; if(c%r==0) // 无解挺好的 { Exgcd(a,b,X=0,Y=0); X=X/r*c; ll tmp=abs(b/r); X=(X%tmp+tmp)%tmp; if(!X) X+=tmp; if(X<=min(L[i],L[j])) return 0; } } } return 1; } int main() { int i,m; R(n); for(i=1;i<=n;i++) { R(C[i]); R(P[i]); R(L[i]); m=max(m,C[i]); } for(i=m;;i++) { if(Solve(i)) { Wl(i); break; } } return 0; } /* input 3 1 3 4 2 7 3 3 2 1 output 6 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!