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;
}