zoukankan      html  css  js  c++  java
  • 【BZOJ 4569】 4569: [Scoi2016]萌萌哒 (倍增+并查集)

    4569: [Scoi2016]萌萌哒

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 865  Solved: 414

    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

    【分析】

      这题的方法还是很妙的。虽然说不是怎么新奇但是我还是没想出来嘛。。

      其实个人觉得线段树也是可以的。用线段树上的点表示区间,然后也可以merge。

      倍增也很好打啦。

      f[i][j]表示[i,i+2^j-1]这个区间,同层的区间可以merge。

      m个操作的时候就merge最多log个区间嘛。最后把merge的并查集下放到区间长度小一倍那里就好。

      要细心一点,若全都在一个并查集,答案应该是10而不是9。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Mod 1000000007
     8 #define Maxn 100010
     9 #define Maxd 20
    10 
    11 int f[Maxn][Maxd],num[Maxn][Maxd],fa[Maxn*Maxd];
    12 int son[Maxn*Maxd][2];
    13 
    14 int ffa(int x)
    15 {
    16     if(fa[x]!=x) fa[x]=ffa(fa[x]);
    17     return fa[x];
    18 }
    19 
    20 void merge(int st1,int st2,int l)
    21 {
    22     for(int j=18;j>=0;j--)
    23     {
    24         if((1<<j)<=l)
    25         {
    26             int x=num[st1][j],y=num[st2][j];
    27             if(ffa(x)!=ffa(y)) fa[ffa(x)]=y;
    28             if((1<<j)<l) merge(st1+(1<<j),st2+(1<<j),l-(1<<j));
    29             return;
    30         }
    31     }
    32 }
    33 
    34 int main()
    35 {
    36     int n,m;
    37     scanf("%d%d",&n,&m);
    38     int cnt=0;
    39     for(int j=0;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) 
    40     {
    41         num[i][j]=++cnt;
    42         if(j!=0) son[cnt][0]=num[i][j-1],son[cnt][1]=num[i+(1<<j-1)][j-1];
    43     }
    44     for(int i=1;i<=cnt;i++) fa[i]=i;
    45     for(int i=1;i<=m;i++)
    46     {
    47         int l1,r1,l2,r2;
    48         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    49         merge(l1,l2,r1-l1+1);
    50     }
    51     for(int j=18;j>0;j--)
    52     {
    53         for(int i=1;i<=n;i++) if(num[i][j])
    54         {
    55             if(ffa(num[i][j])!=num[i][j])
    56             {
    57                 int x=num[i][j],y=ffa(num[i][j]);
    58                 if(ffa(son[x][0])!=ffa(son[y][0])) fa[ffa(son[x][0])]=son[y][0];
    59                 if(ffa(son[x][1])!=ffa(son[y][1])) fa[ffa(son[x][1])]=son[y][1];
    60             }
    61         }
    62     }
    63     int ans=1,tot=0;
    64     for(int i=1;i<=n;i++) if(ffa(num[i][0])==num[i][0])
    65     {
    66         tot++;
    67         if(ans==1) ans=1LL*ans*9%Mod;
    68         else ans=1LL*ans*10%Mod;
    69     }
    70     if(tot==1) ans=10;
    71     printf("%d
    ",ans);
    72     return 0;
    73 }
    View Code

    2017-04-27 15:02:37

  • 相关阅读:
    XMLHTTP使用具体解释
    C++之EOF()
    具体解释VB中连接access数据库的几种方法
    Android中部署自己的su
    hdoj 1052 Tian Ji -- The Horse Racing【田忌赛马】 【贪心】
    【C/C++多线程编程之九】pthread读写锁
    数据结构课程设计题目十二_计算机学院学生会的打印机(优先队列)
    百度开发人员面试题(优化)
    为Windows 7的winsxs目录瘦身,谨慎。
    sonix uvc驱动的加入 RT5350支持H264
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6774320.html
Copyright © 2011-2022 走看看