【LG3295】[SCOI2016]萌萌噠
阿新 • • 發佈:2019-03-16
isdigit -- text sco gist 長度 online begin getch
【LG3295】[SCOI2016]萌萌噠
題面
洛谷
題解
考慮現在我們如果一次只是限定兩個位置相等該怎麽做,
直接將這些位置用並查集並起來然後答案就是
\[
ans=
\begin{cases}
10 & n=1\\
9\times 10^{t-1} & \text{otherwise}
\end{cases}
\]
其中\(t\)為聯通塊的個數。
現在我們是給定兩個區間,我們將這兩個區間中的數兩兩並起來算,復雜度\(O(n^2)\)。
考慮優化上面的過程:
維護\(\log n\)個並查集,第\(i\)個並查集維護的是區間長度為\(2^i\)的區間相等的情況。
那麽我們每次只要合並兩個並查集就行了。
高層的並查集顯然對下面的無影響,我們到最後將下層合並到上層,最後統計底層並查集聯通塊個數即可。
代碼
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; inline int gi() { register int data = 0, w = 1; register char ch = 0; while (!isdigit(ch) && ch != '-') ch = getchar(); if (ch == '-') w = -1, ch = getchar(); while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); return w * data; } const int Mod = 1e9 + 7; const int MAX_N = 1e5 + 5; int N, M, lg[MAX_N], bin[20]; int f[20][MAX_N]; int getf(int *p, int x) { return p[x] == x ? x : p[x] = getf(p, p[x]); } void merge(int len, int x, int y) { x = getf(f[len], x), y = getf(f[len], y); if (x != y) f[len][x] = y; } int main () { #ifndef ONLINE_JUDGE freopen("cpp.in", "r", stdin); #endif N = gi(), M = gi(); if (N == 1) return puts("9") & 0; bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1; for (int i = 2; i <= N; i++) lg[i] = lg[i >> 1] + 1; for (int i = 0; bin[i] <= N; i++) for (int j = 1; j <= N; j++) f[i][j] = j; while (M--) { int l1 = gi(), r1 = gi(), l2 = gi(), r2 = gi(); int len = lg[r1 - l1 + 1]; merge(len, l1, l2); merge(len, r1 - bin[len] + 1, r2 - bin[len] + 1); } for (int i = lg[N]; i; i--) for (int j = 1; j + bin[i] - 1 <= N; j++) { merge(i - 1, j, getf(f[i], j)); merge(i - 1, j + bin[i - 1], getf(f[i], j) + bin[i - 1]); } int ans = 9, cnt = 0; for (int i = 1; i <= N; i++) if (getf(f[0], i) == i) ++cnt; for (int i = 1; i < cnt; i++) ans = 10ll * ans % Mod; printf("%d\n", ans); return 0; }
【LG3295】[SCOI2016]萌萌噠