P2421-荒岛野人Savage题解
好久没写题解了啊
洛谷P2421 荒岛野人
题目大意:有一个有很多洞的岛上,住了\(n\)个野人,每个野人的初始位置为\(c[i]\),换洞的速度为\(p[i]\),寿命为\(l[i]\)。要求求出洞的最少个数\(M\)满足每个野人在生存状态下不会在同一年和其他野人住在同一个山洞里。
概括版:很多个青蛙的约会。
首先根据题目 我们可以得出一个式子:
\[c[i]+p[i]\times t\equiv c[j]+p[j]\times t \pmod M (t\le min(l[i],l[j]))
\]
其中 \(t\)为经过的年数,\(M\)为我们要求出的结果。
显然,如果上面的式子成立,说明这个结果食补满足题意的。
因此,我们的目的就可以简化为:求不满足上述式子的\(M\)的最小值。
当然,如果\(x>min(l[i],l[j])\),说明有野人已经死亡,之后式子恒成立。
题目给出 \(M\le 1e6\),所以直接枚举即可得出答案。
$check$函数部分推导过程
由
\[c[i]+p[i]\times t\equiv c[j]+p[j]\times t \pmod M (t\le min(l[i],l[j]))
\]
得
\[c[i]-c[j]+t\times (p[i]-p[j])=k\times M
\]
移项可得
\[t\times (p[j]-p[i])+k\times M=c[i]-c[j]
\]
之后套入扩展欧几里得公式即可
$\large{code}$
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
inline int qr()
{
char ch=getchar();int x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
#define qr qr()
const int Ratio=0;
const int N=25;
const int maxx=INT_MAX;
int n,m=0,ans;
int s[N],p[N],l[N];
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int c=exgcd(b,a%b,y,x);
y-=a/b*x;
return c;
}
bool check(int ii)
{
// cout<<i<<endl;
fo(i,1,n)
fo(j,i+1,n)
{
int c=s[i]-s[j],b=ii,a=p[j]-p[i],x,y;
int d=exgcd(a,b,x,y);
if(c%d)
continue;
a/=d,b/=d,c/=d;
if(b<0)
b=-b;
x=(x*c%b+b)%b;
//找到解 如果这两个人都还活着 就false
if(x<=l[i]&&x<=l[j])
return false;
}
return true;
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=qr;
fo(i,1,n)
s[i]=qr,p[i]=qr,l[i]=qr,m=max(m,s[i]);
for(int i=m;;i++)
if(check(i))
{
// cout<<i<<endl;
printf("%d\n",i);
break;
}
return Ratio;
}