zoukankan      html  css  js  c++  java
  • BZOJ 4569 萌萌哒

    题目传送门

    4569: [Scoi2016]萌萌哒

    Time Limit: 10 Sec Memory Limit: 256 MB

    Submit: 483 Solved: 221

    [Submit][Status][Discuss]

    ## **Description** 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条 件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...S r2完全相同。比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,13 1141不满足条件,前者数的长度不为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 ## **题解** 这道题显然要用并查集,不过需要进行区间合并。所以我最开始选择了线段树···· 在经历千辛万苦之后,我确定了线段树并不能搞定此题。 看此题数据,我们就蒙一个$O(nlog (n))$级的算法。这样我们可以用f[i][j]来表示一段区间的父亲。 最暴力的方法就是表示i..j区间的父亲,但显然会炸。我们就联想到倍增,用f[i][j]表示i..i+(2^j)-1的区间父亲。 这样我们对于每一个区间的合并,我们最多进行$log n$次合并,在算上并查集的$O(alpha (a))$ ,总的复杂度为$O(nlog n alpha (a))$ 。 ``` c++ #include //Input char Inc; int Ina; inline int geti() { while ((Inc = getchar()) < '0' || Inc > '9'); Ina = Inc - '0'; while ((Inc = getchar()) >= '0' && Inc <= '9') Ina = (Ina << 3) + (Ina << 1) + Inc - '0'; return Ina; } // const int Mod = 1e9 + 7, N = 100005; int f[N][17]; bool vis[N]; int find(int i, int j) { return (f[i][j] ^ i) ? f[i][j] = find(f[i][j], j) : i; }

    void Union(int k, int i, int j) {
    if (find(i, k) ^ find(j, k)) {
    f[f[i][k]][k] = f[j][k];
    if (!k--) return;
    Union(k, i, j); Union(k, i + (1 << k), j + (1 << k));
    }
    }

    int main() {
    int n, m, i, j, a, b, c, d, ans;
    n = geti(), m = geti();
    if (n < 2) return puts("9"), 0;
    for (j = 0; (1 << j) <= n; ++j)
    for (i = 1; i + (1 << j) - 1 <= n; ++i)
    f[i][j] = i;
    while (m--) {
    a = geti(), b = geti(), c = geti(), d = geti();
    j = b - a + 1, i = 0;
    while ((1 << i + 1) <= j) ++i;
    Union(i, a, c); Union(i, b - (1 << i) + 1, d - (1 << i) + 1);
    }
    ans = 9; vis[find(1, 0)] = true;
    for (i = 2; i <= n; ++i) if (!vis[find(i, 0)]) vis[find(i, 0)] = true, ans = 10LL * ans % Mod;
    printf("%d ", ans);
    return 0;
    }

  • 相关阅读:
    Advanced Installer文件和文件夹页面中的临时文件操作
    celery使用方法
    网站高并发之道
    大话程序猿眼里的高并发
    StringTokenizer类的使用
    linux下查看最消耗CPU、内存的进程
    分享10条PHP性能优化的小技巧,帮助你更好的用PHP开发:
    json 除去转义字符以及查看json错误
    关于 redis、memcache、mongoDB 的对比
    QPS 与 TPS 简介
  • 原文地址:https://www.cnblogs.com/cycleke/p/5838890.html
Copyright © 2011-2022 走看看