• bzoj4569 [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
     
    正解:$ST$表+并查集。
    首先我们可以想到一个$O(n^{2})$的暴力,那就是把所有相等的数用并查集弄起来,最后统计联通块个数计算答案就行了。
    然后考虑如何优化。本能反应是想到线段树,但是线段树是没有办法维护的。
    那么我们可以考虑$ST$表,虽然我也不知道怎么想到这一步。。
    如果两个区间要求相等,那么我们就把每个区间分成两个区间,然后分别用并查集连起来。
    最后我们直接把并查集的父亲标记下放,在最底层统计连通块个数就行了。
     
     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 #define rhl (1000000007)
    14 #define inf (1<<30)
    15 #define N (100010)
    16 #define il inline
    17 #define RG register
    18 #define ll long long
    19 #define pos(i,j) (((i)-1)*20+(j)+1)
    20 
    21 using namespace std;
    22 
    23 int fa[22*N],vis[22*N],leg[N],n,m,tot;
    24 
    25 il int gi(){
    26     RG int x=0,q=1; RG char ch=getchar();
    27     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    28     if (ch=='-') q=-1,ch=getchar();
    29     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    30     return q*x;
    31 }
    32 
    33 il ll qpow(RG ll a,RG ll b){
    34     RG ll ans=1;
    35     while (b){
    36     if (b&1) ans=ans*a%rhl;
    37     a=a*a%rhl,b>>=1;
    38     }
    39     return ans;
    40 }
    41 
    42 il int find(RG int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); }
    43 
    44 il void unionn(RG int u,RG int v,RG int leg){
    45     RG int x=find(pos(u,leg)),y=find(pos(v,leg));
    46     if (x!=y) fa[x]=y; return;
    47 }
    48 
    49 int main(){
    50 #ifndef ONLINE_JUDGE
    51     freopen("mmd.in","r",stdin);
    52     freopen("mmd.out","w",stdout);
    53 #endif
    54     n=gi(),m=gi(); for (RG int i=2;i<=n;++i) leg[i]=leg[i>>1]+1;
    55     for (RG int j=0;j<=19;++j) for (RG int i=1;i<=n;++i) fa[pos(i,j)]=pos(i,j);
    56     for (RG int i=1,l1,r1,l2,r2,len;i<=m;++i){
    57     l1=gi(),r1=gi(),l2=gi(),r2=gi(),len=r1-l1+1,unionn(l1,l2,leg[len]);
    58     unionn(r1-(1<<leg[len])+1,r2-(1<<leg[len])+1,leg[len]);
    59     }
    60     for (RG int j=19;j;--j)
    61     for (RG int i=1,x;i<=n;++i)
    62         if (i+(1<<j)-1<=n && find(pos(i,j))!=pos(i,j)){
    63         x=(find(pos(i,j))-1)/20+1,fa[find(pos(i,j-1))]=find(pos(x,j-1));
    64         fa[find(pos(i+(1<<(j-1)),j-1))]=find(pos(x+(1<<(j-1)),j-1));
    65         }
    66     for (RG int i=1;i<=n;++i) if (!vis[find(pos(i,0))]) vis[find(pos(i,0))]=1,++tot;
    67     printf("%lld
    ",9*qpow(10,tot-1)%rhl); return 0;
    68 }
  • 相关阅读:
    应用Solaris11放置光盘修复solaris引导妨碍
    HP 3803TX 装置debian4 Linux
    释放linux细碎的内存
    linux批量查找文件内容
    Oracle 10g R2 for Solaris x86在Solaris 11上的装配
    Linux 零碎进修之shell剧本进修
    华硕易PC台式机版7月环球上市 或运转Linux
    Linux文件琐细 一分钱一分货
    linux下平安管理
    预装Windows或Ubuntu,戴尔出Mini Inspiron 8.9寸笔记本
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7260160.html
Copyright © 2020-2023  润新知