【NOI2002荒岛野人】(扩展欧几里得算法)

题意:给你N组Ci,Pi,Li,求一个最小的M,满足对于任意的一对i,j,都有:

C_i+P_i*x\equiv\ C_j+L_j*x(mod\ M)无解或者最小正整数解x满足x<=min(L_i,L_j)。(也就是有一个先老掉了)。

该方程可以转化为:

C_i+P_i*x-M*y=C_j+P_j*x 

(P_i-P_j)*x-M*y=C_j-C_i 

于是转化为枚举M,每次用扩展欧几里得一一检查是否合法。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=16;
int N,c[MAXN],p[MAXN],l[MAXN];

LL t,g;
LL exgcd(int a,int b,LL &x,LL &y)
{
	if(!b) {x=1;y=0;return a;}
	g=exgcd(b,a%b,x,y);
	t=x; x=y; y=t-(a/b)*y;
	return g;
}

int check(int T)
{
	int i,j;
	LL x,y,gcd,t0;
	for(i=1;i<=N;i++)
	for(j=i+1;j<=N;j++)
	{
		gcd=exgcd(p[i]-p[j],-T,x,y);
		if((c[j]-c[i])%gcd!=0) continue;
		x=x*(c[j]-c[i])/gcd;
		t0=abs(-T/gcd);
		x=(x%t0+t0)%t0;
		if(!x) x+=t0;
		if(x<=min(l[i],l[j])) return 0;
	}
	return 1;
}

int main()
{
	int i,MAX=0;
	scanf("%d",&N);
	for(i=1;i<=N;i++)
	{
		scanf("%d%d%d",&c[i],&p[i],&l[i]);
		MAX=max(MAX,c[i]);
	}
		
	for(i=MAX;;i++)
		if(check(i))
			break;
	printf("%d",i);
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/82348239