首页 > 代码库 > UVA 10413 - Crazy Savages(数论)

UVA 10413 - Crazy Savages(数论)

UVA 10413 - Crazy Savages

题目链接

题意:一个岛上有一些山洞,有n个幸存者,每个幸存者初始在山洞Ci,山洞是形成一个环的,每天每个人都会走Pi,然后Li天后该人会死掉,要求一个最小的山洞数使得每个人在活着的时候都不会碰面(因为碰面就会发生冲突)

思路:枚举山洞数m,然后两两判断会不会碰面
判断的方法是:两个人其实就是两个线性方程
(c1+p1k1)%m=x(c2+p2k2)%m=x 如果两人会在同一天碰面,那么两人k值相同,两式相减后得到(c1?c2)+k(p1?p2)=ym,移项后得到一个线性方程
ax+by=c,a=(p1?p2),b=?m,c=(c2?c1),然后利用扩展欧几里得算法去求解判断有没有解在[0,min(k1, k2)]中,如果有就是会发生冲突,不满足

代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
int t, n;
struct People {
    int c, p, l;
    void read() {
	scanf("%d%d%d", &c, &p, &l);
    }
} p[20];

bool cmp(People a, People b) {
    return a.l > b.l;
}

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

bool judge(People A, People B, int mod) {
    int a = A.p - B.p;
    int b = -mod;
    int c = B.c - A.c;
    int x, y;
    int d = exgcd(a, b, x, y);
    if (c % d) return false;
    int down = -INF, up = INF;
    int tmp = min(A.l, B.l);
    if (b / d < 0) {
	down = max(down, (int)ceil((tmp * d - x * c) * 1.0 / b));
	up = min(up, (int)floor(-x * c * 1.0 / b));
    }
    else {
	down = max(down, (int)ceil(-x * c * 1.0 / b));
	up = min(up, (int)floor((tmp * d - x * c) * 1.0 / b));
    }
    return down <= up;
}

bool solve(int mod) {
    for (int i = 0; i < n; i++)
	for (int j = i + 1; j < n; j++)
	    if (judge(p[i], p[j], mod))
		return false;
    return true;
}

int main() {
    scanf("%d", &t);
    while (t--) {
	scanf("%d", &n);
	int down = 0;
	for (int i = 0; i < n; i++) {
	    p[i].read();
	    down = max(down, p[i].c);
	}
	for (int i = down; i <= 1000000; i++) {
	    if (solve(i)) {
		printf("%d\n", i);
		break;
	    }
	}
    }
    return 0;
}