P3295 萌萌哒

题目

一个长度为n的大数,用\(S_1,S_2,S_3...S_n\)表示,其中\(S_i\)表示数的第\(i\)位,\(S_1\)是数的最高位,告诉你一些限制条件,每个条
件表示为四个数,\(l_1,r_1,l_2,r_2\),即两个长度相同的区间,表示子串\(S_{l_1},S_{l_1+1},S+{l_1+2}...S_{r_1}\)\(S_{l_2},S_{l_2+1},S_{l_2+2}...S_{r2}\)完全相同。比如\(n=6\)时,某限制条件\(l_1=1,r_1=3,l_2=4,r_2=6\),那么\(123123\)\(351351\)均满足条件,但是\(12012\)\(131141\)不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

输入格式

第一行两个数\(n\)\(m\),分别表示大数的长度,以及限制条件的个数。接下来\(m\)行,对于第\(i\)行,有4个数\(l_{i_1},r_{i_1},l_{i_2},r_{i_2}\),分别表示该限制条件对应的两个区间。

\(1≤n≤10^5,1≤m≤10^5,1≤l_{i_1},r_{i_1},l_{i_2},r_{i_2}≤n\)并且保证\(r_{i_1}-l_{i_1}=r_{i_2}-l_{i_2}\)

输出格式

一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模 \(10^9+7\)的结果即可。

输入样例

4 2
1 2 3 4
3 3 3 3

输出样例

90

题解

这道题使用并查集和ST表

\(f\)\(ST\)表数组, \(f_{i,j}\)表示\([i,i+2^j-1]\)

一个条件可以拆成\(log\)份,然后再合并。

\(f_{s,t}\)\(f_{i,j}\)在同一集合,则\(f_{s,t-1}\)\(f_{i,j-1}\)以及\(f_{s+2^{t-1}-1,t-1}\)\(f_{i+2^{j-1}-1,j-1}\)都在同一集合。

为了满足条件,一层一层的做,把下一层的合并,编号大的合进编号小。

\(tot\)为集合个数

答案就是\(9*10^(tot-1)\)

代码

#include <cmath>
#include <cstdio>
using namespace std;
int n, m, fa[100005][18], ans;
int find(int x, int k) { return fa[x][k] == x ? x : fa[x][k] = find(fa[x][k], k); }
void join(int x, int y, int k) { if ((x = find(x, k)) != (y = find(y, k))) fa[x][k] = y; }
int main() {
    scanf("%d %d", &n, &m);
    int maxk = floor(log2(n));
    for (int i = 1; i <= n; ++i)
        for (int k = 0; k <= maxk; ++k) fa[i][k] = i;
    for (int i = 1, l1, r1, l2, r2; i <= m; ++i) {
        scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
        for (int k = maxk; ~k; --k)
            if (l1 + (1 << k) - 1 <= r1)
                join(l1, l2, k), l1 += 1 << k, l2 += 1 << k;
    }
    for (int k = maxk; k; --k)
        for (int i = 1; i + (1 << k) - 1 <= n; ++i) {
            int pos = find(i, k);
            join(i, pos, k - 1);
            join(i + (1 << k - 1), pos + (1 << k - 1), k - 1);
        }
    for (int i = 1; i <= n; ++i)
        if (fa[i][0] == i) ans = !ans ? 9 : ans * 10ll % 1000000007;
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/youxam/p/p3295.html