NOIP模拟测试7

考爆了,爆零,GG.

T1:方程的解

一眼Exgcd,求出最小解,再求出所有解。

然而Exgcd忘了,面向数据范围编程,特判少了,40分滚粗。

这题要特判的多了。。。

  1. 要注意特判0
  2. 要注意特判符号
  3. 要注意特判有无正整数解

大体来说就是这3条,关于符号的问题,Exgcd肯定要正数,可以先把负数标记一下,取相反数,Exgcd后再改回来。

关于Exgcd,有必要再证明一下。。。

已知不定方程\(ax + by = c\),首先由某不记得名字的推论,它有解的必要条件为 \((a, b) | c\).

我们设\(g = (a, b)\),先求解\(ax + by = g\).

因为\((a, b) = (b, a % b), a % b = a - b * \lfloor \frac{a}{b} \rfloor\),所以\(bx + (a - b * \lfloor \frac{a}{b} \rfloor)y = g\).即:\(ay + b(x - \lfloor \frac{a}{b} \rfloor y) = g\).

可得原方程一组解 \(x_1 = y, y_1 = x - \lfloor \frac{a}{b} \rfloor y\).

\(c = kg\),我们令该不定方程两边同乘\(k\)\(ax_0 + by_0 = c\), 其中\(x_0 = kx_1, y_0 = ky_1\).

这是原方程的一组特解。要获得同解,我们让\(x + \Delta x, y + \Delta y\). \(a(x_0 + \Delta x) + b (y_0 + \Delta y) = c\).为使方程平衡,\(a \Delta x = b \Delta y\).

所以\(\Delta x = \frac{b}{g}, \Delta y = \frac{a}{g}\).

原方程同解为$x = x_0 + t \frac{b}{g}, y = y_0 - t \frac{a}{g}, t \in Z $.

求出刚好大于0的y,求出刚好大于0的x对应的最大y,差值除以步长\(\frac{a}{g}\)再+1就是答案。

本题过于难调,\(Have\ fun\ debugging!\) (逃

#include <bits/stdc++.h>
#define ll long long

ll Exgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1, y = 0; return a;
    }
    ll r = Exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return r;
}

ll Solve(ll a, ll b, ll c) {
    bool opa = 0, opb = 0;
    if (a == 0 && b == 0) return c == 0 ? -1 : 0;
    if (a == 0) return (c == 0 || (c % b == 0 && c / b > 0)) ? -1 : 0;
    if (b == 0) return (c == 0 || (c % a == 0 && c / a > 0)) ? -1 : 0;
    if (c < 0) a = -a, b = - b, c = -c;
    if (a < 0) a = -a, opa = 1;
    if (b < 0) b = -b, opb = 1;
    ll x, y;
    ll g = Exgcd(a, b, x, y);
    if (c % g != 0) return 0;
    ll t = c / g;       x *= t, y *= t, a /= g, b /= g, c = t;
    if (opa) a = -a, x = -x;
    if (opb) b = -b, y = -y;
    if (a < 0) a = -a, b = -b, c = -c;
    if (a * b < 0) return -1;
    x %= b;
    while (x <= 0) x += b;
    y = (c - a * x) / b;
    if (y < 0) return 0;
    ll y_min = y % a;
    while (y_min <= 0) y_min += a;
    return y_min <= y ? (y - y_min) / a + 1 : 0;
}

signed main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        ll a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);
        ll ans = Solve(a, b, c);
        if (ans == -1 || ans > 65535) puts("ZenMeZheMeDuo");
        else printf("%lld\n", ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/gekoo/p/11227861.html