题目归档 #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;
}

浙公网安备 33010602011771号