zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    暑假集训单切赛第二场 UVA 10982 Troublemakers
    暑假集训单切赛第一场 POJ 2309 BST(找规律的题)
    暑假集训单切赛第一场 CF 191A Dynasty Puzzles
    暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)
    暑假集训单切赛第一场 UVA 1737 Mnemonics and Palindromes 3
    大一暑假集训第六周第一场单切赛
    POJ 1486 Sorting Slides(寻找必须边)
    【机器学习】梯度下降法的相关介绍
    Linux下使用Tmux提高终端环境下的效率
    Fedora23安装以后要做的优化配置
  • 原文地址:https://www.cnblogs.com/youxam/p/p3295.html
Copyright © 2011-2022 走看看