Solution -「SCOI 2016」萌萌哒

cirnovsky /

§ Description

Link.

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

§ Solution

Let us only consider one limit ([l1,r1],[l2,r2])([l_{1},r_{1}],[l_{2},r_{2}]), the number of ways is 10rl+110^{r-l+1}. Connecting every i[l1,r1]i\in[l_{1},r_{1}] and j[l2,r2]j\in[l_{2},r_{2}], we can construct a graph. Counting the number of connected subgraphs, denoted as xx, the answer is 9×10x19\times10^{x-1}, and the complexity is O(n2α(n))\mathcal{O}(n^{2}\alpha(n)). Each interval could be splited into log2rl+1\log_{2}r-l+1 subintervals, so that we can solve this in O(nlog2nα(n))\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;
}