Loading

题目归档 #5

目录及链接

[POJ2142] The balance

解题

显然的扩展欧几里得算法。可能刚开始会觉得情况有些多,实际上可以缩减为只有两个情况,然后比较即可。

解方程 \(ax+by=d\) ,然后对解出来的 \(x,y\) 取绝对值即可。

代码

#include <iostream>
#include <cstring>
#include <cstdio>

#define LL long long

using namespace std;

LL read() {
	LL x = 0, f = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while('0' <= c && c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}

LL gcd(LL a, LL b) {
	if(!b) return a;
	else return gcd(b, a % b);
}

void exgcd(LL a, LL b, LL &x, LL &y) {
	if(!b) {
		x = 1, y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		LL cpx = x;
		x = y, y = cpx - (a / b) * y;
	}
}

int main() {
	LL a, b, d;
	while(true) {
		bool flag = 0;
		a = read(); b = read(); d = read();
		if(a < b) swap(a, b), flag = 1;
		if(!a && !b && !d) break;
		LL GCD = gcd(a, b), modx = b / GCD, mody = a / GCD, x, y, x1, y1, x2, y2;
		exgcd(a, b, x, y);
		x *= (d / GCD), y *= (d / GCD);
		x1 = (x % modx + modx) % modx, y1 = (d - a * x1) / b;
		y2 = (y % mody + mody) % mody, x2 = (d - b * y2) / a;
		if(y1 < 0) y1 = -y1;
		if(x2 < 0) x2 = -x2;
		if(!flag) {
			if(x1 + y1 < x2 + y2) printf("%lld %lld\n", x1, y1);
			else if(x1 + y1 > x2 + y2) printf("%lld %lld\n", x2, y2);
			else if(a * x1 + b * y1 < a * x2 + b * y2) printf("%lld %lld\n", x1, y1);
			else printf("%lld %lld\n", x2, y2);
		}
		else {
			if(x1 + y1 < x2 + y2) printf("%lld %lld\n", y1, x1);
			else if(x1 + y1 > x2 + y2) printf("%lld %lld\n", y2, x2);
			else if(a * x1 + b * y1 < a * x2 + b * y2) printf("%lld %lld\n", y1, x1);
			else printf("%lld %lld\n", y2, x2);
		}
	}
	return 0;
}

[POJ2417] Discrete Logging

解题

\(\texttt{BSGS}\) 算法板子题。没啥可说的。

只是这道题时空都有点卡就很捞。

程序

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>

#define LL long long

using namespace std;

LL p, a, b;
map <LL, LL> vis;

LL Pow(LL a, LL b) {
	LL ans = 1, base = a;
	while(b) {
		if(b & 1) ans = ans * base % p;
		base = base * base % p;
		b >>= 1;
	}
	return ans;
}

void work() {
	if(b == 1) {
		printf("0\n");
		return;
	}
	vis.clear();
	LL res = 1, k = sqrt(p) + 1;
	LL inva = Pow(a, p - 2);
	vis[1] = k;
	for(LL i = 1; i <= k - 1; ++i) {
		res = res * a % p;
		vis[res] = i;
		if(res == b) {
			printf("%lld\n", i);
			return;
		}
	}
	LL num = 1, mul = Pow(inva, k);
	for(LL i = k; i <= p; i += k) {
		num = mul * num % p;
		res = num * b % p;
		if(vis[res]) {
			printf("%lld\n", i + (vis[res] == k ? 0 : vis[res]));
			return;
		}
	}
	printf("no solution\n");
}

int main() {
	while(scanf("%lld%lld%lld", &p, &a, &b) != EOF) work();
	return 0;
}

[POJ2891] Strange Way to Express Integers

解题

扩展中国剩余定理 (EXCRT) 板子题,luogu 上也有对应的板子。

很恶心的地方就是这道题可能会乘法溢出,所以要上「龟速乘」。

程序

#include <iostream>
#include <cstring>
#include <cstdio>

#define Maxk 1000010
#define LL long long

using namespace std;

LL read() {
	LL x = 0, f = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while('0' <= c && c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}

LL K, r[Maxk], m[Maxk];

LL gcd(LL a, LL b) {
	if(!b) return a;
	else return gcd(b, a % b);
}

void exgcd(LL a, LL b, LL &x, LL &y) {
	if(!b) {
		x = 1, y = 0;
		return;
	}
	else {
		exgcd(b, a % b, x, y);
		LL cpx = x;
		x = y, y = cpx - (a / b) * y;
	}
}

LL mul(LL a, LL b, LL p) {
	LL flag = 1;
	if(b < 0) flag = -1, b = -b;
	LL ans = 0, base = a;
	while(b) {
		if(b & 1) ans = (ans + base) % p;
		base = (base * 2) % p;
		b >>= 1;
	}
	return ans * flag;
}

int main() {
	while(scanf("%Ild", &K) != EOF) {
		memset(m, 0, sizeof(m));
		memset(r, 0, sizeof(r));
		for(int i = 1; i <= K; ++i) {
			m[i] = read(); r[i] = read();
		}
		LL x, y;
		bool flag = 0;
		for(int i = 1; i < K; ++i) {
			LL GCD = gcd(m[i], m[i + 1]), mod = m[i + 1] / GCD;
			if((r[i + 1] - r[i]) % GCD) {
				printf("-1\n");
				flag = 1;
				break;
			}
			exgcd(m[i], m[i + 1], x, y);
			x = mul(x, ((r[i + 1] - r[i]) / GCD % mod + mod) % mod, mod);
			x = (x % mod + mod) % mod;
			r[i + 1] = x * m[i] + r[i];
			m[i + 1] /= GCD; m[i + 1] *= m[i];
		}
		if(flag) continue;
		printf("%lld\n", r[K]);
	}
	return 0;
}
posted @ 2020-08-02 14:00  Sqrtyz  阅读(86)  评论(0)    收藏  举报