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;
}

UVA 10413 - Crazy Savages(数论),布布扣,bubuko.com

时间: 2024-12-28 13:56:01

UVA 10413 - Crazy Savages(数论)的相关文章

uva 10413 - Crazy Savages(拓展欧几里得)

题目链接:uva 10413 - Crazy Savages 题目大意:一座山有m个山洞,形成一个圈,现在有n个部落的人,每个部落一开始住在ci山洞,第2天会向后面移动pi个位置,一共会在这座山住li天.现在如果两个部落在同一个山洞相遇,则会发生战争,问说m最小时多少的时候,保证不会发生争斗. 解题思路:因为每个部落都有自己的存在时间,所以枚举m,然后枚举两个部落,判断他们有没有可能相遇. 假设在第k天: ci+k?pi=a?m???(1) cj+k?pj=b?m???(2) 由(2)-(1)得

uva 10560 - Minimum Weight(数论)

题目连接:uva 10560 - Minimum Weight 题目大意:给出n,问说至少需要多少个不同重量的砝码才能称量1~n德重量,给出所选的砝码重量,并且给出k,表示有k个重量需要用上述所选的砝码测量. 解题思路:重量为1的砝码肯定要选,它可以表示到1的重量,那么下一个砝码的重量肯定选择3(2?1+1),这样1,3分别可以用一个砝码表示,而2,4分别为3-1和3+1,这样1~4的重量也都可以表示.于是有公式ai=si?1?2+1. #include <cstdio> #include &

uva 11105 - Semi-prime H-numbers(数论)

题目链接:uva 11105 - Semi-prime H-numbers 题目大意:H-number为4?k+1(k为非负数),H-composites为因子中含有H-number(不包括自己本身)的数,反之久是H-prime,给定n,求有多少H-composites. 解题思路:首先用筛选法求出范围内的H-prime,然后枚举两个判断乘积是否在范围内. #include <cstdio> #include <cstring> const int maxn = 1e6+5; ty

UVA 11754 - Code Feat(数论)

UVA 11754 - Code Feat 题目链接 题意:给定一个c个x, y1,y2,y3..yk形式,前s小的答案满足s % x在集合y1, y2, y3 ... yk中 思路:LRJ大白例题,分两种情况讨论 1.所有x之积较小时候,暴力枚举每个集合选哪个y,然后中国剩余定理求解 2.所有x之积较大时候,选定一个k/x尽可能小的序列,枚举x * t + y (t = 1, 2, 3...)去暴力求解. 代码: #include <stdio.h> #include <string.

UVA 718 - Skyscraper Floors(数论)

UVA 718 - Skyscraper Floors 题目链接 题意:在一个f层高的楼上,有e个电梯,每个电梯有x,y表示y + k * x层都可以到,现在要问从a层能否到达b层(中间怎么换乘电梯不限制) 思路:对于两个电梯间能不能换乘,只要满足y[i] + xx x[i] == y[j] + yy y[j].然后移项一下,就可以用拓展欧几里得求解,进而求出x,y的通解,然后利用通解范围x' >= 0, y' >= 0, x[i] x' + y[i] <= f, x[j] y' + y

UVA 10692 - Huge Mods(数论)

UVA 10692 - Huge Mods 题目链接 题意:求a0a1a2...mod m 思路:直接算肯定不行,利用欧拉定理ab=a(b mod phi(m) + phi(m))(b>=phi(m)),对指数进行降值处理,然后就可以利用快速幂去计算了,计算过程利用递归求解. 代码: #include <stdio.h> #include <string.h> const int N = 1005; int phi[N * 10], vis[N * 10], m, n, a[

uva 718 - Skyscraper Floors(数论+bfs)

题目链接:uva 718 - Skyscraper Floors 题目大意:一栋大楼,有F层楼,E个电梯,现在要从A层到B层,问是否可行,每个电梯给出Xi和Yi,代表这个电梯可以到达的层数Yi+k?Xi(k≥0) 解题思路:建图,以A,B以及电梯为节点建图,将可以到达A,B这两层的电梯与这两点建边,在将两两电梯可以达到同一层的建边,判断方法为:Yi+aXi=Yj+bXj,移项得:aXi+bXj=Yj?Yi,即是一个线性方程,用拓展欧几里得算法求出通解的形式,判断是否存在通解在0~F之间即可. #

UVA 10623 - Thinking Backward(数论)

UVA 10623 - Thinking Backward 题目链接 题意:给定一个数量,求用圆,椭圆,三角形分割平面,分割出该数量,输出所有情况 思路:有公式2 + 2m(m-1) + n(n-1) + 4mn + 3p(p-1) + 6mp + 6np 由于m和p都是[0,100],所以可以枚举m和p,去求出n,然后判断合不合适 代码: #include <stdio.h> #include <string.h> #include <math.h> #include

uva 11728 - Alternate Task(数论)

题目链接:uva 11728 - Alternate Task 题目大意:给出S,求N,要求N所有的因子和为S. 解题思路:枚举因子i,所有整除i的数和加上i. #include <cstdio> #include <cstring> const int N = 1005; int n, c[N], v[N]; void init () { memset(c, 0, sizeof(c)); memset(v, -1, sizeof(v)); for (int i = 1; i &l