码迷,mamicode.com
首页 > 其他好文 > 详细

[SCOI2016]萌萌哒

时间:2018-02-28 17:30:10      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:输出   bsp   合并   hid   getchar   输入输出格式   std   body   radius   

题目描述

一个长度为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的结果即可。

 

输入输出样例

输入样例#1: 
4 2
1 2 3 4
3 3 3 3
输出样例#1: 
90
正解:
首先想到对于相同的数可以放到一个集合里,用并查集维护
有多少个集合(假设有cnt个集合)
那么最后答案就是ans=9*(10^(cnt-1))%mod
证明:第一个位置数字可以为9种(不能为0)
     第二个位置数字可以为10种(0-9)
第三个位置数字可以为10种(0-9)
.........
一共有cnt个位置,即ans;
但是暴力的话,很明显会超时,怎们办呢?
我们可以用st表维护。
某个区间看成一个节点,他的两个儿子拼起来即为自身区间
(按照倍增的区间分法)
当进行合并的时候,我们对区间进行合并而不是点。
最后,我们按照区间长度从大到小依次考察每个区间,
如果他并不是一个独立的区间,那么我们就把他的限制
放给他的儿子,即合并操作,直到区间长度为1
到最后统计一下集合的个数就可以得出答案

技术分享图片
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<string>
 6 #include<cmath>
 7 #define ll long long
 8 #define DB double
 9 #define inf 214748360000
10 #define mod 1000000007
11 using namespace std;
12 inline int read()
13 {
14     int x=0,w=1;char ch=getchar();
15     while(!isdigit(ch)){if(ch==-) w=-1;ch=getchar();}
16     while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-0,ch=getchar();
17     return x*w;
18 }
19 const int N=1e5+90;
20 int n,fa[N*18],m,cnt,ch[N*18][2];
21 int f[N][18];
22 int F(int x)
23 {
24     if(x==fa[x]) return x;
25     else return fa[x]=F(fa[x]);
26 }
27 void merge(int x,int y)
28 {
29     int fx=F(x),fy=F(y);
30     fa[fx]=fa[fy]=fx;
31 }
32 int main()
33 {
34     n=read();m=read();
35     for(int j=0;(1<<j)<=n;++j)
36      for(int i=1;i+(1<<j)-1<=n;++i)
37      {
38          f[i][j]=++cnt;fa[cnt]=cnt;
39          if(j)
40          {
41              ch[cnt][0]=f[i][j-1];
42              ch[cnt][1]=f[i+(1<<(j-1))][j-1];
43          }
44      }
45     while(m--)
46     {
47          int l1,r1,l2,r2;
48          l1=read();r1=read();l2=read();r2=read();
49          int j=log2(r2-l2+1);
50          merge(f[l1][j],f[l2][j]);
51          merge(f[r1-(1<<j)+1][j],f[r2-(1<<j)+1][j]);
52     }
53     for(int i=cnt;i>n;--i)
54     {
55         int t=F(i);
56         if(t!=i)
57         {
58             merge(ch[i][0],ch[t][0]);
59             merge(ch[i][1],ch[t][1]);
60         }
61     }
62     cnt=0;
63     for(int i=1;i<=n;++i)
64      cnt+=(F(i)==i);
65     int ans=9;
66     for(int i=1;i<=cnt-1;++i)
67      ans=1ll*ans*10%mod;
68     printf("%d",ans);
69     return 0;
70 }
View Code
走到悬崖处,想办法,就有路了(搭个梯子??)。

[SCOI2016]萌萌哒

标签:输出   bsp   合并   hid   getchar   输入输出格式   std   body   radius   

原文地址:https://www.cnblogs.com/adelalove/p/8484346.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!