1. 程式人生 > >bzoj4569-[Scoi2016]萌萌噠

bzoj4569-[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,後者第二位與第五位不同。問滿足以上所有條件的數有多少個。

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

Sample Output

90

Solution

發現約束條件等價於若干組 \(S_{l_{i1} + d} = S_{l_{i2} + d}\).

這樣就可以用並查集維護, 時間複雜度 \(O(m*n*\alpha (n))\).

考慮每次都是一段連續的區間, 利用倍增優化:
fa[l][p]表示起點為p, 長度為l的區間的父親;
最後查詢時, 從\(l\) 合併到\(l-1\), 一直到0.

Code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//---------------------------------------
const int nsz=1e5+50,lnsz=25;
const ll nmod=1e9+7;
int n,m,ln,cnt;
int fa[lnsz][nsz];
void inituf(){rep(i,0,ln)rep(j,1,n)fa[i][j]=j;}
int getfa(int a,int l){return fa[l][a]==a?a:fa[l][a]=getfa(fa[l][a],l);}
void merge(int a,int b,int l){
    a=getfa(a,l),b=getfa(b,l);
    if(a!=b)fa[l][a]=b;
}
void p(){
    repdo(i,ln,0){
        printf("l=%d ",i);
        rep(j,1,n)printf("%d ",getfa(j,i));
        printf("\n");
    }
}
ll qp(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%nmod;
        b>>=1,a=a*a%nmod;
    }
    return res;
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n>>m;
    ln=22;
    int a,b,c,d;
    inituf();
    rep(i,1,m){
        cin>>a>>b>>c>>d;
        repdo(j,ln,0){
            if(a+(1<<j)-1<=b)merge(a,c,j),a+=(1<<j),c+=(1<<j);
        }
//      p();
    }
    repdo(i,ln,1){
        repdo(j,n-(1<<i)+1,1){
            merge(j,getfa(j,i),i-1);
            merge(j+(1<<(i-1)),getfa(j,i)+(1<<(i-1)),i-1);
        }
    }
    rep(i,1,n)if(getfa(i,0)==i)++cnt;
    cout<<9ll*qp(10,cnt-1)%nmod<<'\n';
    return 0;
}