• 【bzoj4569 scoi2016】萌萌哒


    题目描述

    一个长度为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,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

    输入输出格式

    输入格式:

    第一行两个数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。

    输出格式:

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

    题意:

    给出长度为n,并且有m个限制l1,r1,l2,r2,指区间l1-r1和l2-r2的数完全相同,求最后数的可能性;

    题解:
    ①笨拙的我首先考虑暴力算法,枚举i = l1 to l2,然后把l1-r1和l2-r2的元素一一合并(并查集),但是太慢了。。。。。。。。

    ②太慢加速就好了,引入倍增并查集
    考虑f[x][y]为第x层,第一个位置为y,f[x][y]代表的x层区间y,y+(1<<x)-1的合并情况,每次我们把l1-r1区间长度二进制拆分后与l2-r2的对应拆分区间在正确的x上合并,统计答案的时候,如果f[x][y]和另一个标号为
    fa的区间合并了,那么就让x-1层的y和fa合并,y+(1<<x-1)和fa+(1<<x-1)合并;

     

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 const int N = 100010,mod = 1e9+7;
     5 int n,m,f[N][20],p[20];
     6 char gc(){
     7     static char *p1,*p2,s[1000000];
     8     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
     9     return(p1==p2)?EOF:*p1++;
    10 }
    11 int rd(){
    12     int x = 0; char c = gc();
    13     while(c<'0'||c>'9') c = gc();
    14     while(c>='0'&&c<='9') x=x*10+c-'0',c=gc();
    15     return x;
    16 }
    17 int find(int j,int k){
    18     return(f[j][k]==j)?j:f[j][k]=find(f[j][k],k);
    19 }
    20 void Union(int l1,int l2,int k){
    21     if(find(l1,k) != find(l2,k)) 
    22     f[f[l1][k]][k] = f[l2][k];
    23 }
    24 int main()
    25 {    freopen("bzoj4569.in","r",stdin);
    26     freopen("bzoj4569.out","w",stdout);
    27     n=rd();m=rd();
    28     for(int i= p[0] = 1;i <= 17;i++) p[i] = p[i-1]<<1;
    29     for(int i = 0;i <= 17;i++)
    30     for(int j = 1;j <= n;j++){
    31     if(j+p[i]-1>n) break;
    32     f[j][i] = j;        
    33     }
    34     for(int i = 1,l1,l2,r1,r2,len;i <= m;i++){
    35         l1=rd(),r1=rd(),l2=rd(),r2=rd();
    36         for(int k = 17;k >= 0;k--) if(l1+p[k]-1<=r1) {
    37             Union(l1,l2,k);
    38             l1=l1+p[k],l2=l2+p[k];
    39         } 
    40     }
    41     for(int i = 17;i >= 1;i--)
    42         for(int j = 1;j+p[i]-1<=n;j++){
    43             if(find(j,i)!=j) 
    44             {
    45             Union(j,f[j][i],i-1);
    46             Union(j+p[i-1],f[j][i]+p[i-1],i-1);    
    47             }
    48     }
    49     int tot = 0,ans=9,tmp = 10;
    50     for(int i = 1;i <= n;i++) 
    51     if(find(i,0)==i) tot++;
    52     tot--;while(tot){if(tot&1) ans=1ll*ans*tmp%mod; tot>>=1; tmp = 1ll*tmp*tmp%mod;}
    53     printf("%d
    ",ans);
    54     return 0;
    55 }//by tkys_Austin;

     

     

  • 相关阅读:
    Amoeba+Mysql实现数据库读写分离
    分布式mysql中间件(mycat)
    mysql打不开表问题解决方案
    redis下载安装以及添加服务
    linux mysql重启命令
    Centos打开、关闭、结束tomcat,及查看tomcat运行日志
    mybaties中,模糊查询的几种写法
    如何给mysql用户分配权限+增、删、改、查mysql用户
    反人类的MyEclipse之-Javascript双引号自动补全
    反人类的MyEclipse之-调整JavaScript代码-花括号换行显示
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/8647253.html
Copyright © 2020-2023  润新知