洛谷 P1516 青蛙的约会

题目链接

Solution

先列出最简单的柿子:

\[(X+mT) \% L=(Y+nT) \% L \]

下面推导过程:

\[(X + mT) \% L = (Y + nT) \% L \]

\[⇒ X + mT \equiv Y + nT (\%L) \]

\[⇒ (m-n)T \equiv Y-X (\% L) \]

其中 \(m-n\), \(Y-X\) 已知,分别设为 \(a\), \(c\), 上面的柿子可以写成如下形式:

\[aT + yL = c \]

如果用 \(x\) 表示 \(T\)\(b\) 表示 \(L\),这个柿子还可以变成更优美的形式:

\[ax + by = c \]

\[(a=m-n, b=L, c=Y-X) \]

这就变成线性同余方程的一般柿子了。

考虑用 exgcd 求出一组对于 \(ax+by=gcd(a,b)\) 的特解,记为 \(x_0\), \(y_0\)。显然:

\[ax_0+by_0=gcd(a, b) \]

\[⇒ ax_0 \frac{c}{gcd(a,b)} +by_0 \frac{c}{gcd(a,b)} = gcd(a,b) \frac{c}{gcd(a,b)} \]

\[⇒ a \frac{x_0c}{gcd(a,b)} + b \frac{y_0c}{gcd(a,b)} = c \]

于是我们对原方程求出了一组特解:

\[x = \frac{x_0c}{gcd(a,b)}, y = \frac{y_0c}{gcd(a,b)} \]

考虑通解。设 \(x, y\) 是已求出的特解,则有:

\[ax+by=a(x+bd)+b(y-ad) \]

要使 \(bd, ac\) 最小且为整数,\(d\) 的最小值为 \(\frac{1}{gcd(a,b)}\)。因此:

\[x_{min}=x \% \frac{b}{gcd(a,b)} \]

注意负数取模。

另外,如果计算前 \(a\) 是负数,就对 \(a\)\(c\) 取相反数。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

long long X, Y, m, n, l, a, b, c, x, y, g;

long long gcd(long long x, long long y) { return y == 0 ? x : gcd(y, x % y); } 

void exgcd(long long a, long long b)
{
    if(b == 0)
    {
        x = 1, y = 0;
        return ;
    }
    exgcd(b, a % b);
    long long tx = x;
    x = y, y = tx - (a / b) * y;
}

int main()
{
    scanf("%lld%lld%lld%lld%lld", &X, &Y, &m, &n, &l);
    a = m - n, b = l, c = Y - X, g = gcd(a, b);
    if(a < 0) a = -a, c = -c;
    g = gcd(a, b);
    if(c % g != 0) { printf("Impossible"); return 0; }
    exgcd(a, b);
    printf("%lld", ((x * (c / g)) % (b / g) + (b / g)) % (b / g));
    return 0;
}
posted @ 2020-09-27 17:53  Nyxia  阅读(105)  评论(0编辑  收藏  举报