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

Posted wls001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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\n",ans);
37 }
View Code

 





以上是关于[BZOJ4569][Scoi2016]萌萌哒 倍增+并查集的主要内容,如果未能解决你的问题,请参考以下文章

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

bzoj 4569: [Scoi2016]萌萌哒

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

BZOJ4569: [Scoi2016]萌萌哒

BZOJ4569 [Scoi2016]萌萌哒

bzoj4569 [Scoi2016]萌萌哒