Solution -「SCOI 2016」萌萌哒

Description

Link.

给定一个长度为 \(n\) 的数组让你填数,需要满足 \(m\) 个形如 \(([l_{1},r_{1}],[l_{2},r_{2}])\) 的要求,这两个区间填好后需要一样,问方案数。

Solution

Let us only consider one limit \(([l_{1},r_{1}],[l_{2},r_{2}])\), the number of ways is \(10^{r-l+1}\).
Connecting every \(i\in[l_{1},r_{1}]\) and \(j\in[l_{2},r_{2}]\), we can construct a graph.
Counting the number of connected subgraphs, denoted as \(x\), the answer is \(9\times10^{x-1}\), and the complexity is \(\mathcal{O}(n^{2}\alpha(n))\).
Each interval could be splited into \(\log_{2}r-l+1\) subintervals, so that we can solve this in \(\mathcal{O}(n\log_{2}n\alpha(n))\).

#include <bits/stdc++.h>
typedef long long ll;
#define sf(x) scanf("%d",&x)
#define ssf(x) scanf("%lld",&x)
struct DSU {
    int fa[100010];
    void init(int l) {
        std::iota(fa + 1, fa + l + 1, 1);
    }
    int find(int x) {
        return (x ^ fa[x]) ? fa[x] = find(fa[x]) : x;
    }
    void ins(int x, int y) {
        if (x ^ y)
            fa[x] = y;
    }
} dsu[20];
int n, m, opl0, opr0, opl1, opr1;
ll ans = 1;
int main() {
    sf(n), sf(m);

    for (int i = 0; i ^ 20; ++i)
        dsu[i].init(n);

    while (m-- > 0) {
        sf(opl0), sf(opr0), sf(opl1), sf(opr1);
        int cur0 = opl0, cur1 = opl1;

        for (int i = 19; ~i; --i) {
            if (cur0 + (1 << i) - 1 <= opr0) {
                dsu[i].ins(dsu[i].find(cur0), dsu[i].find(cur1));
                cur0 += (1 << i);
                cur1 += (1 << i);
            }
        }
    }

    for (int j = 19; j; --j) {
        for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
            dsu[j - 1].ins(dsu[j - 1].find(i), dsu[j - 1].find(dsu[j].find(i)));
            dsu[j - 1].ins(dsu[j - 1].find(i + (1 << (j - 1))), dsu[j - 1].find(dsu[j].find(i) + (1 << (j - 1))));
        }
    }

    for (int i = 1; i <= n; ++i)
        if (dsu[0].fa[i] == i)
            ans = ans * (ans == 1 ? 9 : 10) % 1000000007;

    printf("%lld\n", ans);
    return 0;
}
posted @ 2021-05-11 14:05  cirnovsky  阅读(54)  评论(0编辑  收藏  举报