其实就是模版。
void ex_gcd(LL a, LL b,LL &x, LL &y)
{
if (!b){
x = 1; y = 0;
return;
} else {
ex_gcd(b, a % b, x, y);
int t = x;
x = y; y = t - a / b * y;
}
}
除法表达式有如下的形式: X1/X2/X3…/Xk,其中 Xi 是正整数且 Xi<=1000000000 (1 <= i <= k, k <=10000)。除法表达式应当按照从左到右的顺序求,例如表达式1/2/1/2 的值为 1/4. 但可以在表达式中加入括号来改变计算顺序,例如 (1/2)/(1/2) 的值为 1. 现给出一个除法表达式 E,求是告诉是否可以通过增加括号来使其为E’, E’ 为整数。
首先E’一定可以表示成 X / Y 的形式。那么我们考虑分子分母上分别有那些数:第一,X1 一定出现在分子上。第二,不论怎么加括号 X2一定出现在分母上。第三其余的都可以出现在分子上。总之一句话,只有 X2 一定出现在分母上 —— X1/[X2/(X3/.../Xk)] ①。也就是说如果 ① 式是个整数,那么 E’就可以是整数,否则不论怎么加括号都不可能使E’为整数,因为 X2 总在分母上且总不能被消去。那么我们用分别求出 gcd(X2, Xi), 然后X2/gcd(X2, Xi)。如果最后 X2 为 1,那么可以为整数,否则就说明X2 总有不能被消去的因子。
#include
using namespace std;
const int MAX_N = 10005;
int T, n, a[MAX_N];
void init()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
}
int gcd(int a, int b)
{
return (b == 0) ? a : gcd(b, a % b);
}
bool judge()
{
a[2] /= gcd(a[1], a[2]);
for (int i = 3; i <= n; i ++) a[2] /= gcd(a[i], a[2]);
if (a[2] == 1) return 1;
return 0;
}
void doit()
{
if (judge()) printf("YES\n");
else printf("NO\n");
}
int main()
{
scanf("%d", &T);
while (T --){
init();
doit();
}
return 0;
}
有两只青蛙分别在一个长度为 L的环的 X 处和 Y 处,第一只每次可以跳 M 个单位距离,而第二只可以跳 N 个,问最少跳几次后能相遇,如果不能输出 "Impossible"。
设跳了 t 次,X 青蛙跳的距离可以表示为:X + Mt;Y 青蛙跳的距离可以是:Y + Nt,而如果他们相遇,那么他们的距离的差一定是 L 的倍数,因为是个环。所以我们可以得到式子:X + Mt - Y - Nt = k * L,所以 (M - N) * t - k * L = Y - X。利用扩展欧几里德求解。
#include
using namespace std;
typedef long long LL;
long long N, M, x, y, L;
void init()
{
scanf("%lld%lld%lld%lld%lld", &x, &y, &M, &N, &L);
}
LL gcd(LL a, LL b)
{
if (!b) return a;
return gcd(b, a % b);
}
void ex_gcd(LL a, LL b, LL &X, LL &Y)
{
if (!b){ X = 1, Y = 0; return; }
else {
ex_gcd(b, a % b, X, Y);
LL t = X;
X = Y; Y = t - a / b * X;
}
}
void doit(void)
{
LL a = M - N, b = L, c = y - x;
LL g = gcd(a, b);
if (c % g) { printf("Impossible\n"); return; }
LL X, Y;
ex_gcd(a, b, X, Y);
X = X * c / g;
X = (X % b + b) % b;
if (!X) X = b;
printf("%d\n", X);
return;
}
int main(void)
{
init(); doit();
return 0;
}
求 for (int i = a; i <= b; i += c, i %= 1 << k)能执行几次。死循环则输出 "FOREVER"。
其实也就是求 (a + t * c) % (1 << k) = b % (1 << k),也就是t * c - l * (1 << k) = b - a。用扩欧求之。
#include
using namespace std;
typedef long long LL;
LL i, j, l, k;
LL gcd(LL a, LL b)
{
return (b == 0) ? a : gcd(b, a % b);
}
void ex_gcd(LL a, LL b,LL &x, LL &y)
{
if (!b){
x = 1; y = 0;
return;
} else {
ex_gcd(b, a % b, x, y);
int t = x;
x = y; y = t - a / b * y;
}
}
void doit()
{
LL a = l, c = j - i, b = 1;
for (int p = 1; p <= k; p ++) b *= 2;
if (a < 0){
a *= -1; b *= -1;
}
LL x, y, d = gcd(a, b);
if (c % d != 0) { printf("FOREVER\n"); return; }
a /= d; b /= d; c /= d;
ex_gcd(a, b, x, y);
x = (((x * c) % b) + b) % b;
printf("%lld\n", x);
}
int main()
{
while (scanf("%lld%lld%lld%lld", &i, &j, &l, &k) != EOF){
if (i == 0 && j == 0 && l == 0 && k == 0) break;
doit();
}
return 0;
}
一个岛上有若干洞穴排成一个环,有 N个野人,起初分别住在洞穴 Xi,每过一年,他们分别会向前走 Li (每个野人的Li 不同)并住下来,如果一个洞穴要住两个野人的时候,野人就会不高兴,从而使得小岛不安宁。但是令人惊奇的是,小岛从来没有过不安宁的情况,现在请你算出至少要多少个洞穴,才能使小岛永远和平。
很容易想到的算法是枚举 M,然后再用扩欧判断是否合法。但是 M 是 10^6,算算复杂度感觉非常不靠谱。。大约 200000000,每个点0.5s 怎么跑得过?!但是网上的大神们好像都写得这种做法,我有点不明白。希望各位有人能解答我的疑问。
#include
#include
using namespace std;
const int MAX_N = 120;
int n, c[MAX_N], p[MAX_N], l[MAX_N];
int x, y, d, cnt = 0;
void init()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%d%d%d", &c[i], &p[i], &l[i]),
c[i] --,
cnt = max(c[i], cnt);
}
}
void ex_gcd(int a, int b, int &d, int &x, int &y)
{
if (!b){
x = 1; y = 0; d = a;
return;
} else {
ex_gcd(b, a % b, d, x, y);
int t = x;
x = y; y = t - a / b * x;
}
}
bool check(int m)
{
for (int i = 1; i <= n; i ++)
for (int j = i + 1; j <= n; j ++){
int a = p[i] - p[j], b = m, C = c[j] - c[i];
if (a < 0){
a *= -1; C *= -1;
}
ex_gcd(a, b, d, x, y);
if (C % d) continue;
int t = b / d;
x = x * C / d;
while (x < 0) x = x + t;
while (x >= t) x = x - t;
if (x <= l[i] && x <= l[j]) return 0;
}
return 1;
}
void doit()
{
for (int i = cnt + 1; i <= 1000000; i ++)
if (check(i)){ printf("%d\n", i); break; }
return;
}
int main()
{
init();
doit();
return 0;
}