BZOJ 4569 萌萌噠 (並查集)

2021-08-08 18:47:30 字數 1601 閱讀 3972

time limit: 10 sec memory limit: 256 mb

description

乙個長度為n的大數,用s1 s2 s3… sn表示,其中si表示數的第i位,s1是數的最高位,告訴你一些限制條件,每個條

件表示為四個數,l1,r1,l2,r2,即兩個長度相同的區間,表示子串sl1 sl1+1 sl1+2… sr1與sl2 sl2+1 sl2+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

sample output

思路:

因此使用st表維護並查集,從高到低進行類似st表合併的操作,最後判定有多少個代表元素,則每個並查集內的數字一定相同,簡單的乘法原理即可得到答案。

#include

#include

#include

#include

#define ll long long

using

namespace

std;

const

int n = 1e5 + 5, mod = 1e9+7, p = 17;

int n,m;

int fa[n*20],f[n][20],mk[n*20][2],pw[20],tot=0,cnt=0,ans;

int find(int x)

int merge(int x, int y)

inline

int read()

int fpow(int a, int b, int p)

return ret;

}int main()

}for(int j=p; j>0; --j)

for(register

int i=1; i<=n; ++i) //如果任意f[s,t]和f[i,j]屬於同一集合,那麼f[s,t-1]與f[i,j-1]以及f[s+2^(t-1)-1,t-1]和f[i+2^(j-1)-1,j-1]都應該屬於同一集合。

for(register

int i=1; i<=n; ++i)

if( !fa[f[i][0]] ) ++cnt;

ans = 9;//不含前導0

for(register

int i=1; i10 % mod;

}printf("%lld\n", (ll)ans);

return

0;}

BZOJ4569 萌萌噠 倍增 並查集

沒想到這兩個東西還可以這麼用,我們可以用f i j 表示 i i 2 j 1 這一段區間屬於哪乙個集合,沒有則等於0.那麼每次合併我們可以把這個限制拆成log個區間,依次合併起來。若f i j 和f s t 同屬乙個集合,那麼f i j 1 和f s t 1 f i 2j 1 j 1 和f s 2t...

SCOI2016 萌萌噠 並查集 倍增

傳送門 一開始是想賭一把,把節點乙個乙個的unite,然後懷著wa的心情wa了。然後又準備用離散去優化,然後又懷著wa的心情wa了。萬般無奈去查題解,發現竟然要使用倍增?倍增是啥,我多少年沒有用過了 複習了一波倍增,原來倍增也可以用在並查集上,我對並查集又有了新的理解,這個資料結構,好強啊!incl...

SCOI2016 萌萌噠 倍增 並查集

乙個長度為n的大數,用s1s2s3.sn表示,其中si表示數的第i位,s1是數的最高位,告訴你一些限制條件,每個條件表示為四個數,l1,r1,l2,r2,即兩個長度相同的區間,表示子串sl1sl1 1sl1 2.sr1與sl2sl2 1sl2 2.sr2完全相同。比如n 6時,某限制條件l1 1,r...