LibreOJ#3144. 「APIO 2019」奇怪装置 – 题解

主要思路

自己推了三个假的循环,遂奔向题解。

先考虑设循环节为 \(k\),且考虑最终 \(x = 0, y = 0\) 的局势。我们考虑怎样的循环节才能迭代一次、得到同样的 \(x = 0, y = 0\) 的局势。不妨直接带入 \(k\):

\[ x = (k + \lfloor \frac{k}{B} \rfloor) \bmod A, y = k \bmod B \]

此时终局势为 \(x = 0, y = 0\),那么可以得到信息 \(B | k\)。此时下取整已经没有效益,得:

\[ \begin{aligned} k + \frac{k}{B} &\equiv 0 \pmod A \\ k(B + 1) &\equiv 0 \pmod A \end{aligned} \]

算完这玩意之后,我们可以突破模意义的限制得到:

\[ \begin{aligned} k(B + 1) &= Ai \\ k &= i \cdot \frac{A}{B + 1} \end{aligned} \]

由于 \(k\) 是个整数,则 \(i\) 需要满足:

\[ i = j \frac{B + 1}{\gcd(A, B + 1)} \]

再加上 \(B | k\) 的条件,很容易得到:

\[ i = j B \frac{B + 1}{\gcd(A, B + 1)} \]

那么循环节就是:

\[ \begin{aligned} k &= j B \frac{B + 1}{\gcd(A, B + 1)} \cdot \frac{A}{B + 1} \\ &= j \frac{AB}{\gcd(A, B + 1)} \\ k &\equiv 0 \pmod {\frac{AB}{\gcd(A, B + 1)}} \end{aligned} \]

代码

// LOJ3144.cpp
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MAX_N = 1e6 + 200;

ll n, A, B, loop, cnt;
pair<ll, ll> segs[MAX_N << 1];

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

int main()
{
    scanf("%lld%lld%lld", &n, &A, &B);
    loop = A / gcd(A, B + 1) * B;
    for (int i = 1; i <= n; i++)
    {
        ll l, r;
        scanf("%lld%lld", &l, &r);
        if (r - l + 1 >= loop)
            printf("%lld\n", loop), exit(0);
        l %= loop, r %= loop;
        if (l <= r)
            segs[++cnt] = make_pair(l, r);
        else
            segs[++cnt] = make_pair(l, loop - 1), segs[++cnt] = make_pair(0, r);
    }
    sort(segs + 1, segs + 1 + cnt);
    segs[++cnt] = make_pair(loop + 1, 0);
    ll lft = segs[1].first, rig = segs[1].second, ans = 0;
    for (int i = 2; i <= cnt; i++)
    {
        if (rig < segs[i].first)
        {
            ans += rig - lft + 1;
            lft = segs[i].first, rig = segs[i].second;
        }
        else
            rig = max(rig, segs[i].second);
    }
    printf("%lld\n", ans);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *