「APIO 2019」奇怪装置

题目

考虑推柿子

最开始的想法是如果两个\(t\)\(mod\ B\)意义下相等,那么只需要比较一下\((t+\left \lfloor \frac{t}{B}\rfloor \right)mod\ A\)就好了

显然\(t=t\% B+B\times \lfloor \frac{t}{B} \rfloor\)

于是第一维就是$t%B+(B+1)\times \lfloor \frac{t}{B} \rfloor $

也就是说如果\(t\%B\)的是相等的,那么只要\((B+1)\times \lfloor \frac{t}{B} \rfloor\)\(mod\ A\)意义下是相等的,那么两个\(t\)就是本质相同的

考虑求一下后面那个东西的循环节,显然是\(\frac{lcm(B+1,A)}{B+1}=\frac{A}{gcd(b+1,A)}\)

再考虑到\(t\%B\)的循环节是\(B\),所以整个的循环节就是\(\frac{AB}{gcd(B+1,A)}\),也就是说\(t\)\(t+\frac{AB}{gcd(B+1,A)}\)是本质相同的

由此我们把这个问题转化成了一个\(mod\ \frac{AB}{gcd(B+1,A)}\)意义的区间覆盖,我们只需要把这些区间放上去覆盖就好了,最后就是求一下被覆盖的总面积,这个是一个非常普及的贪心问题

非常丢人的写错了区间覆盖

代码

#include <bits/stdc++.h>
#define re register
#define max std::max
#define LL long long
inline LL read() {
    LL x = 0;char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3ll) + (x << 1ll) + c - 48, c = getchar();
    return x;
}
int n, m;
LL A, B, L;
const int maxn = 1e6 + 5;
struct Seg {LL l, r;} a[maxn], b[maxn << 1];
LL gcd(LL a, LL b) { return !b ? a : gcd(b, a % b); }
inline void add(LL x, LL y) { b[++m].l = x, b[m].r = y; }
inline int cmp(Seg A, Seg B) { return A.l == B.l ? A.r > B.r : A.l < B.l; }
int main() {
    n = read(), A = read(), B = read();
    for (re int i = 1; i <= n; i++) a[i].l = read(), a[i].r = read();
    for (re int i = 1; i <= n; i++) L = max(L, a[i].r);L++;
    LL r = gcd(A, B + 1);
    if (A / r <= L / B) L = A / r * B;
    for (re int i = 1; i <= n; i++) {
        LL x = a[i].r / L - a[i].l / L;
        if (x >= 2) {add(0, L - 1);break;}
        if (x == 1)
            add(0, a[i].r % L), add(a[i].l % L, L - 1);
        else
            add(a[i].l % L, a[i].r % L);
    }
    std::sort(b + 1, b + m + 1, cmp);
    int p = 1;LL ans = 0;
    for (re int i = 1; i <= m; i = p) {
        LL T = b[i].r;
        while (b[p].l <= T && p <= m) T = max(T, b[p].r), p++;
        ans += T - b[i].l + 1;
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2019-06-26 17:49  asuldb  阅读(258)  评论(0编辑  收藏  举报