BZOJ 4569: [Scoi2016]萌萌哒

Description

一个长度为n的大数,用S1S2S3…Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2…Sr1与Sl2Sl2+1Sl2+2…Sr2完全相同。比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,131141不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

Input

第一行两个数n和m,分别表示大数的长度,以及限制条件的个数。接下来m行,对于第i行,有4个数li1,ri1,li2,ri2,分别表示该限制条件对应的两个区间。
1≤n≤10^5,1≤m≤10^5,1≤li1,ri1,li2,ri2≤n;并且保证ri1-li1=ri2-li2。

Output

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

Sample Input

4 2
1 2 3 4 
3 3 3 3

Sample Output

90

Solution

倍增+并查集

大块合并减少小块合并次数

Code

#include <cstdio>
#include <algorithm>

#define PROB "rmq_union_set"
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1000000007;
const int maxn = 100005;
const LL P = INF;
inline int getint() {
    int r = 0; bool b = true; char c = getchar();
    while ('0' > c || c > '9') {if (c == '-') b = false; c = getchar();}
    while ('0' <= c && c <= '9') {r = r * 10 + (c - '0'); c = getchar();}
    if (b) return r;
    return -r;
}

// struct edge_T {int to, next;} edge[maxn<<1];

int f[20][maxn], T[maxn];

int Find(int k, int x) {
    if (f[k][x] == x) return x;
    return f[k][x] = Find(k, f[k][x]);
}

void mer(int k, int x, int y) {
    int a = Find(k, x), b = Find(k, y);
    if (a != b) {
        f[k][a] = b;
        if (k)
        {
            mer(k-1, x, y);
            mer(k-1, x+(1<<(k-1)), y+(1<<(k-1)));
        }
    }
}

LL ksm(LL a, LL b) {
    LL ret = 1ll, tmp = a;
    while (b) {
        if (b & 1ll) ret = (ret * tmp) % P;
        tmp = (tmp * tmp) % P;
        b >>= 1ll;
    }
    return ret;
}

int n, m, l1, r1, l2, r2, x;
int main() {
//  freopen(PROB".in", "r", stdin);
//  freopen(PROB".out", "w", stdout);

    n = getint(); m = getint();
    T[0] = -1;
    for (int i = 1; i <= n; ++i) {
        T[i] = T[i>>1] + 1;
        for (int j = 0; j < 20; ++j) f[j][i] = i;
    }
    for (int i = 0; i < m; ++i) {
        l1 = getint(); r1 = getint();
        l2 = getint(); r2 = getint();
        x = T[r1-l1+1];
        mer(x, l1, l2);
        mer(x, r1-(1<<x)+1, r2-(1<<x)+1);
    }

    LL ans = -1ll;
    for (int i = 1; i <= n; ++i) if (Find(0, i) == i) ++ans;
    printf("%lld", ksm(10ll, ans) * 9ll % P);

    fclose(stdin);
    fclose(stdout);

    return 0;
}
  1. maghsk说道:

    LOL!代码高亮搞定啦!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据