一个长度为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,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
第一行两个数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。
一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模10^9+7的结果即可。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#define nn 100011
using namespace std;
const long long mod=1e9+7;
int fa[nn][25],log_2;
int read()
{
int ans=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
while(isdigit(ch)) {ans=ans*10+ch-‘0‘;ch=getchar();}
return ans*f;
}
int find(int x,int l)
{
return fa[x][l]==x? x:fa[x][l]=find(fa[x][l],l);
}
void merge(int a,int b,int l)
{
int f1=find(a,l),f2=find(b,l);
if(f1==f2) return;
fa[f1][l]=f2;
if(!l) return;
l--;
merge(a,b,l);
merge(a+(1<<l),b+(1<<l),l);
}
int main()
{
long long res=9;
int n,m,l1,r1,l2,r2,len,num=-1;
n=read();m=read();
if(n==1)
{
printf("9");
return 0;
}
for(int i=1;i<=n;i++)
for(int j=0;j<=18;j++)
fa[i][j]=i;
for(int i=1;i<=m;i++)
{
l1=read();r1=read();l2=read();r2=read();
len=log2(r1-l1+1);
if(l1<l2)
swap(l1,l2),swap(r1,r2);
merge(l1,l2,len);merge(r1-(1<<len)+1,r2-(1<<len)+1,len);
}
for(int i=1;i<=n;i++)
if(find(i,0)==i)
num++;
for(int i=1;i<=num;i++)
res=res*(long long)10%mod;
printf("%lld",res);
return 0;
}
/*
5 3
2 3 1 2
1 5 1 5
4 4 3 3
*/