• [BZOJ4569][Scoi2016]萌萌哒 倍增+并查集


    4569: [Scoi2016]萌萌哒

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1262  Solved: 610
    [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

    HINT

     

    Source

    考虑朴素算法,对每个询问的每一位进行合并,复杂度O(N*N)

    我们发现其中有许多重复限制,我们要考虑减少重复计算本质上相同的限制,于是我们用倍增优化

    f[i][j]表示[i,i+2^j-1]这一区间的情况

    对于每一个限制,可以拆成两个大的限制,然后逐层向下传递,直到某一层的两个区间处于同一集合,也就说明这次限制之前已经又过了,就不需要再向下处理。

    复杂度O(NlgN)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define maxn 100005
     8 using namespace std;
     9 int fa[maxn][20];
    10 int find(int x,int t) {return fa[x][t]==x?fa[x][t]:fa[x][t]=find(fa[x][t],t);}
    11 void merge(int x,int y,int t) {
    12     int fx=find(x,t),fy=find(y,t);
    13     if(fx==fy) return;
    14     fa[fx][t]=fy;
    15     if(!t) return;
    16     merge(x,y,t-1);merge(x+(1<<(t-1)),y+(1<<(t-1)),t-1);
    17 }
    18 int n,m;
    19 int lg[maxn];
    20 bool vis[maxn];
    21 int main() {
    22     scanf("%d%d",&n,&m);
    23     for(int i=1;(1<<i)<=n;i++) lg[1<<i]++;
    24     for(int i=1;i<=n;i++) lg[i]+=lg[i-1];
    25     for(int i=1;i<=n;i++) for(int j=0;j<20;j++) fa[i][j]=i;
    26     for(int i=1;i<=m;i++) {
    27         int l1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    28         int len=r1-l1+1;
    29         merge(l1,l2,lg[len]);merge(r1-(1<<lg[len])+1,r2-(1<<lg[len])+1,lg[len]); 
    30     }
    31     long long ans=9;vis[find(1,0)]=1;
    32     for(int i=2;i<=n;i++) {
    33         if(!vis[find(i,0)]) ans*=10ll,ans%=1000000007;
    34         vis[find(i,0)]=1;
    35     }
    36     printf("%lld
    ",ans);
    37 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    nodejs install
    taobao sass
    Cors 跨域访问API
    多文件上传
    Next
    实用小工具
    下载包含src,tgz,zip的文件
    HTML5文件API
    Bootstrap (导航、标签、面包屑导航)
    Bootstrap 固定定位(Affix)
  • 原文地址:https://www.cnblogs.com/wls001/p/8391022.html
Copyright © 2020-2023  润新知