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

[SCOI2016]萌萌哒 解题报告

时间:2020-01-14 23:53:17      阅读:98      评论:0      收藏:0      [点我收藏+]

标签:并查集   log   span   ret   暴力   ref   存储结构   scanf   对应关系   

[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}\). (不能有前导零).


考虑优化.

首先想到线段树优化连边, 但是发现用线段树的话, 无法确定区间的对应关系.


为了连边之后依旧能确定区间的对应关系, 我们需要对每一个点都有一个以它为起点的存储结构.

所以, 我们可以弄一个类似于 ST表 的东西, 但理解方式类似于 线段树.

把整个序列分成 \(\log n\) 层, 每一层之间进行连边.

在给定了 l1,r1,l2,r2 时, 用类似于ST表查询最值时的操作, 把 \([l1,r1]\)\([l2,r2]\) 分别分成两个长度为 \(2\) 的若干次方的区间, 然后在这几个区间之间连边.

在所有边都连完后, 从上往下一层一层地把连边下传, 反映在代码中其实就是并查集的合并.


需要注意的是, 在下传的时候, 设当前层的两个连接区间为 \(A,B\), 我们还需要考虑 \(A\)\(B\) 的子区间, 即下一层的四个区间 \(A_1,A_2\)\(B_1,B_2\) 的连接情况,

\(A_1,A_2\) 是相连的, 就把 \(fa[B_1],fa[B_2]\) 设为 \(fa[A_1]\),

否则, 就把 \(fa[A_1],fa[A_2]\) 设为 \(fa[B_1]\).


代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int _=1e5+7;
const int L=20;
const ll mod=1e9+7;
int n,m,fa[_][L+7],Log[_];
bool vis[_];
ll ans;
void init(){
  cin>>n>>m;
  int t=0;
  for(int i=1;i<=n;i++){
    if(i==1<<(t+1)) t++;
    Log[i]=t;
    for(int k=0;k<=L;k++)
      fa[i][k]=i;
  }
}
int find(int i,int k){ return fa[i][k]==i ?i :fa[i][k]=find(fa[i][k],k); }
void run(){
  int l1,r1,l2,r2;
  int maxn=0;
  for(int i=1;i<=m;i++){
    scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    maxn=max(maxn,max(r1,r2));
    int t=Log[r1-l1+1];
    int f1=find(l1,t),f2=find(l2,t);
    fa[f1][t]=f2;
    f1=find(r1-(1<<t)+1,t),f2=find(r2-(1<<t)+1,t);
    fa[f1][t]=f2;
  }

  for(int k=L;k>=1;k--){
    for(int i=1;i+(1<<k)-1<=n;i++){
      int t=find(i,k),t1=find(i,k-1),t2=find(i+(1<<(k-1)),k-1);
      if(t1==t2){ fa[find(t,k-1)][k-1]=fa[find(t+(1<<(k-1)),k-1)][k-1]=t1; }
      else{ fa[t1][k-1]=find(t,k-1); fa[t2][k-1]=find(t+(1<<(k-1)),k-1); }
    
    }
  }
  int j=find(1,0);
  ans=9; 
  for(int i=2;i<=n;i++)
    if(i!=j&&find(i,0)==i)
      ans=ans*10%mod;
}
int main(){
#ifndef ONLINE_JUDGE
  freopen("x.in","r",stdin);
#endif
  init();
  run();
  printf("%lld\n",ans);
  return 0;
}

[SCOI2016]萌萌哒 解题报告

标签:并查集   log   span   ret   暴力   ref   存储结构   scanf   对应关系   

原文地址:https://www.cnblogs.com/brucew-07/p/12194438.html

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