[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,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
在倍增数组上并查集!
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define LL long long
using namespace std;
const int P = 1e9+7;
const int M = 200001;
int n,m,k,a[M],f[22][M],l1,l2,r1,r2,res=1;
int ff(int x,int y)
{
if(f[y][x]==x) return x;
return f[y][x]=ff(f[y][x],y);}
void link(int x,int y,int len)
{
if(ff(x,len) !=ff(y,len)) f[len][f[len][x]]=f[len][y];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) for(int j=0;j<=20;j++) f[j][i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
for(int j=20;j>=0;j--) if((1<<j)<=r1-l1+1) link(l1,l2,j), l1+=1<<j, l2+=1<<j;
}
for(int j=20;j;j--)
for(int i=1;i+(1<<j)-1<=n;i++)
link(i,ff(i,j),j-1), link(i+(1<<j-1),ff(i,j)+(1<<j-1),j-1);
for(int i=1;i<=n;i++) if(f[0][i]==i) res=(LL)res*10%P;
res=(LL)res*300000003ll%P;
printf("%d",res);
}