bzoj 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不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
Solution
暴力做法就是把相同的合并在一起,最后答案只跟连通块数量有关了
对于每一个限制,合并的复杂度是 \(O(n)\) 的
我们用倍增的思想,也就是 \(st\) 表的思想
假如在合并第 \(k\) 层,且 \(find(i)==find(j)\),说明 \(S[i,i+2^k-1]=S[j,j+2^k-1]\)
也说明第 \(k-1\) 层,\(find(i)==find(j),find(i+1<<(k-1))==find(j+(1<<(k-1)))\)
逐层递推下去就可以得到我们要求的并查集了
#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
int f;char c;
for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=1e5+10,mod=1e9+7;
int n,m,Log[N];
struct ST{
int fa[N];
inline void init(){for(int i=1;i<=n;i++)fa[i]=i;}
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y){fa[find(y)]=find(x);}
}st[25];
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m;
int l1,l2,r1,r2,len;
for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
for(int i=0;i<=Log[n];i++)st[i].init();
for(int i=1;i<=m;i++){
gi(l1);gi(r1);gi(l2);gi(r2);len=Log[r1-l1+1];
st[len].merge(l1,l2);st[len].merge(r1-(1<<len)+1,r2-(1<<len)+1);
}
for(int j=Log[n];j>=1;j--)
for(int i=1;i+(1<<j)-1<=n;i++){
int k=st[j].find(i);
if(i==k)continue;
st[j-1].merge(i,k);
st[j-1].merge(i+(1<<(j-1)),k+(1<<(j-1)));
}
int cnt=0;
for(int i=1;i<=n;i++)if(st[0].find(i)==i)cnt++;
int ans=9;
for(int i=1;i<cnt;i++)ans=1ll*ans*10%mod;
cout<<ans<<endl;
return 0;
}