P2421 [NOI2002]荒岛野人
chuzhitairan · · 题解
思路
看一下数据范围,发现小得可怜,以至于我们可以枚举
下面是AC代码:
#include <bits/stdc++.h>
using namespace std;
int n,C[20],P[20],L[20];
int e_gcd(int a,int b,int& x,int& y)
{
if(!b) {x=1,y=0;return a;}
int ans=e_gcd(b,a%b,x,y);
int t=x;x=y;y=t-(a/b)*y;
return ans;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>C[i]>>P[i]>>L[i];
for(int i=C[n];i<=1000000;i++)
{
int flag=0;
for(int j=1;j<n;j++)
{
for(int k=j+1;k<=n;k++)
{
int a=P[k]-P[j],b=i,c=C[j]-C[k],x,y,gcd,minx;
if(a<0) a=-a,c=-c;
gcd=e_gcd(a,b,x,y);
if(c%gcd!=0) continue;
minx=((x*(c/gcd))%(b/gcd)+(b/gcd))%(b/gcd);
if(minx<=min(L[j],L[k])) {flag=1;break;}
}
if(flag) break;
}
if(!flag) {printf("%d",i);break;}
}
}
接下来是对刚学的扩展欧几里得的一点整理
以这题为例,我们首先从基本问题出发:判断两个野人
其中
如果我们设未知数
那么要解决这题,我们需要知道这个方程:
- 是否有整数解
- 如果有,最小非负整数解是多少
我们先来看第一个问题
如果有整数解,那么
说明
变形一下
对比一下原来的方程,我们惊讶地发现因为常数都一样,所以我们可以由现在方程的解推导出原方程的解,而如果继续这个过程,这不就是辗转相除嘛!辗转相除的结果大家都知道,是
的解就很显然了,是
根据这个解,我们就可以,也肯定可以倒推出原方程的解了。现在再看这段代码
int e_gcd(int a,int b,int& x,int& y)
{
if(!b) {x=1,y=0;return a;}
int ans=e_gcd(b,a%b,x,y);
int t=x;x=y;y=t-(a/b)*y;
return ans;
}
其实就是求
再来看第二个问题
求出了一组特解,再如何找到最小非负整数解呢?假设我们有
一式减二式,得
注意到
那么
minx=((x*(c/gcd))%(b/gcd)+(b/gcd))%(b/gcd);
最后一点要注意的,欧几里得算法求最大公约数只能针对两个非负整数,所以有了这句
if(a<0) a=-a,c=-c;\\b绝对是正数
至此,我学到的扩展欧几里得算是梳理完了(欢迎大佬来补充),当然这个算法还有更多的应用,如乘法逆元、线性同余方程等,解不定方程算是最基础的一种了,必须牢牢掌握ヾ(•ω•`)o