BZOJ4569 : [Scoi2016]萌萌哒

建立ST表,每层维护一个并查集。

每个信息可以拆成两条长度为$2$的幂次的区间相等的信息,等价于ST表里两对点的合并。

然后递归合并,一旦发现已经合并过了就退出。

因为一共只会发生$O(n\log n)$次合并,所以时间复杂度为$O(n\log n\alpha(n))$。

#include<cstdio>
int n,m,i,j,a,b,c,d,f[17][100010],v[100010],ans=9;
int F(int i,int j){return f[i][j]==j?j:f[i][j]=F(i,f[i][j]);}
void merge(int p,int x,int y){
  if(F(p,x)==F(p,y))return;
  f[p][f[p][x]]=f[p][y];
  if(!p)return;
  p--;
  merge(p,x,y),merge(p,x+(1<<p),y+(1<<p));
}
inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;}
int main(){
  read(n),read(m);
  if(n==1)return puts("10"),0;
  for(i=0;(1<<i)<=n;i++)for(j=1;j+(1<<i)-1<=n;j++)f[i][j]=j;
  while(m--){
    read(a),read(b),read(c),read(d);i=31-__builtin_clz(b-a+1);
    merge(i,a,c),merge(i,b-(1<<i)+1,d-(1<<i)+1);
  }
  for(v[F(0,1)]=1,i=2;i<=n;i++)if(!v[F(0,i)])v[f[0][i]]=1,ans=10LL*ans%1000000007;
  return printf("%d",ans),0;
}

  

时间: 2024-10-17 04:53:12

BZOJ4569 : [Scoi2016]萌萌哒的相关文章

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

[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不满足条件,前者数

【BZOJ-4569】萌萌哒 ST表 + 并查集

4569: [Scoi2016]萌萌哒 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 459  Solved: 209[Submit][Status][Discuss] Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2.

bzoj 4569: [Scoi2016]萌萌哒

4569: [Scoi2016]萌萌哒 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不满足条件,前者数的

【BZOJ4569】萌萌哒(并查集,倍增)

[BZOJ4569]萌萌哒(并查集,倍增) 题面 BZOJ 题意: 有一个长度为\(n\)的数 给定\(m\)个限制条件 每次限制\(l1-r1\)与\(l2-r2\)是相同的 求出方案数 题解 如果每次给定的限制都是告诉你某一位和某一位是相同的 那么,我们的做法是: 并查集,然后计算有\(k\)个联通块 \(ans=9*10^{k-1}\) 但是,现在每次给定的都是一个区间 我们不太可能暴力的把区间之间的位置两两进行一次合并 所以,我们来想个办法优化一下. 试试倍增? 维护\(logn\)个并

Luogu P3295 [SCOI2016]萌萌哒(并查集+倍增)

P3295 [SCOI2016]萌萌哒 题面 题目描述 一个长度为 \(n\) 的大数,用 \(S_1S_2S_3 \cdots S_n\) 表示,其中 \(S_i\) 表示数的第 \(i\) 位, \(S_1\) 是数的最高位.告诉你一些限制条件,每个条件表示为四个数, \(l_1,r_1,l_2,r_2\) ,即两个长度相同的区间,表示子串 \(S_{l_1}S_{l_1+1}S_{l_1+2} \cdots S_{r_1}\) 与 \(S_{l_2}S_{l_2+1}S_{l_2+2} \

4569: [Scoi2016]萌萌哒

4569: [Scoi2016]萌萌哒 链接 分析: 每次给出的两个区间长度是一样的,对应位置的数字也是一样的,那么可以将两两对应的数字用并查集合并,设最后有$cnt$个不同的集合,答案就是$9\times 10 ^{cnt-1}$,第一个数不能是0. 暴力合并太慢了,考虑优化.对于一段区间,用倍增的思想分成log段,分别合并log段,最后的下放一下标记即可.类似线段树的懒标记. 代码: #include<cstdio> #include<algorithm> #include&l

SCOI2016萌萌哒题解

SCOI2016萌萌哒题解 题目链接 思路 这个题目大概就是给你一些限制,使区间相等,那么一个很巧妙的思路就是将区间限制转化为两个店在一个并查集里 我们要求的是只有一位的并查集的个数,答案为 ( t我们要求的是只有一位的并查集的个数) 但直接操作复杂度过大 于是有人想到了倍增 f[i][j]表示区间[ , ]所在的并查集 最开始时记录每个大区间的左右儿子 输入 l1 l2 r1 r2时像ST表一样合并 再分别处理每个大区间,如果f[i][j]和f[a][b]在一个并查集里,那么他们的左右儿子也在

[SCOI2016]萌萌哒 解题报告

[SCOI2016]萌萌哒 题意 有一个长度为 \(n\) 的大数, 有 \(m\) 个形如 l1,r1,l2,r2的限制, 表示区间 \([l1,r1]\) 和 \([l2,r2]\) 完全相等, 求满足这些限制的数的个数, 不能含有前导零. \((1 \le n,m \le 10^5)\) 思路 暴力 : 直接 \(O(nm)\) 把相等的数合成一个并查集, 最后若并查集的数量为 \(k\), 则答案为 \(9 \times 10^{k-1}\). (不能有前导零). 考虑优化. 首先想到线

BZOJ 4569 [Scoi2016]萌萌哒 ——ST表 并查集

好题. ST表又叫做稀疏表,这里利用了他的性质. 显然每一个条件可以分成n个条件,显然过不了. 然后发现有许多状态是重复的,首先考虑线段树,没什么卵用. 然后ST表,可以每一层表示对应的区间大小的两个部分是否合并,如果合并就不向下递归. 然后可以剪去许多状态,变成了$O(nlogn)$的. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using n