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不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
Input
第一行两个数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。
Output
一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模10^9+7的结果即可。
Sample Input
4 2
1 2 3 4
3 3 3 3
1 2 3 4
3 3 3 3
Sample Output
90
正解:$ST$表+并查集。
首先我们可以想到一个$O(n^{2})$的暴力,那就是把所有相等的数用并查集弄起来,最后统计联通块个数计算答案就行了。
然后考虑如何优化。本能反应是想到线段树,但是线段树是没有办法维护的。
那么我们可以考虑$ST$表,虽然我也不知道怎么想到这一步。。
如果两个区间要求相等,那么我们就把每个区间分成两个区间,然后分别用并查集连起来。
最后我们直接把并查集的父亲标记下放,在最底层统计连通块个数就行了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define rhl (1000000007) 14 #define inf (1<<30) 15 #define N (100010) 16 #define il inline 17 #define RG register 18 #define ll long long 19 #define pos(i,j) (((i)-1)*20+(j)+1) 20 21 using namespace std; 22 23 int fa[22*N],vis[22*N],leg[N],n,m,tot; 24 25 il int gi(){ 26 RG int x=0,q=1; RG char ch=getchar(); 27 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 28 if (ch=='-') q=-1,ch=getchar(); 29 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 30 return q*x; 31 } 32 33 il ll qpow(RG ll a,RG ll b){ 34 RG ll ans=1; 35 while (b){ 36 if (b&1) ans=ans*a%rhl; 37 a=a*a%rhl,b>>=1; 38 } 39 return ans; 40 } 41 42 il int find(RG int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); } 43 44 il void unionn(RG int u,RG int v,RG int leg){ 45 RG int x=find(pos(u,leg)),y=find(pos(v,leg)); 46 if (x!=y) fa[x]=y; return; 47 } 48 49 int main(){ 50 #ifndef ONLINE_JUDGE 51 freopen("mmd.in","r",stdin); 52 freopen("mmd.out","w",stdout); 53 #endif 54 n=gi(),m=gi(); for (RG int i=2;i<=n;++i) leg[i]=leg[i>>1]+1; 55 for (RG int j=0;j<=19;++j) for (RG int i=1;i<=n;++i) fa[pos(i,j)]=pos(i,j); 56 for (RG int i=1,l1,r1,l2,r2,len;i<=m;++i){ 57 l1=gi(),r1=gi(),l2=gi(),r2=gi(),len=r1-l1+1,unionn(l1,l2,leg[len]); 58 unionn(r1-(1<<leg[len])+1,r2-(1<<leg[len])+1,leg[len]); 59 } 60 for (RG int j=19;j;--j) 61 for (RG int i=1,x;i<=n;++i) 62 if (i+(1<<j)-1<=n && find(pos(i,j))!=pos(i,j)){ 63 x=(find(pos(i,j))-1)/20+1,fa[find(pos(i,j-1))]=find(pos(x,j-1)); 64 fa[find(pos(i+(1<<(j-1)),j-1))]=find(pos(x+(1<<(j-1)),j-1)); 65 } 66 for (RG int i=1;i<=n;++i) if (!vis[find(pos(i,0))]) vis[find(pos(i,0))]=1,++tot; 67 printf("%lld ",9*qpow(10,tot-1)%rhl); return 0; 68 }