【BZOJ 4569】 4569: [Scoi2016]萌萌噠 (倍增+並查集)

4569: [Scoi2016]萌萌噠

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 865  Solved: 414

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的結果便可。ios

Sample Input

4 2
1 2 3 4
3 3 3 3

Sample Output

90

HINT

Source

 

 

【分析】ide

  這題的方法仍是很妙的。雖說不是怎麼新奇可是我仍是沒想出來嘛。。spa

  其實我的以爲線段樹也是能夠的。用線段樹上的點表示區間,而後也能夠merge。code

  倍增也很好打啦。blog

  f[i][j]表示[i,i+2^j-1]這個區間,同層的區間能夠merge。ip

  m個操做的時候就merge最多log個區間嘛。最後把merge的並查集下放到區間長度小一倍那裏就好。string

  要細心一點,若全都在一個並查集,答案應該是10而不是9。it

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Mod 1000000007
 8 #define Maxn 100010
 9 #define Maxd 20
10 
11 int f[Maxn][Maxd],num[Maxn][Maxd],fa[Maxn*Maxd];
12 int son[Maxn*Maxd][2];
13 
14 int ffa(int x)
15 {
16     if(fa[x]!=x) fa[x]=ffa(fa[x]);
17     return fa[x];
18 }
19 
20 void merge(int st1,int st2,int l)
21 {
22     for(int j=18;j>=0;j--)
23     {
24         if((1<<j)<=l)
25         {
26             int x=num[st1][j],y=num[st2][j];
27             if(ffa(x)!=ffa(y)) fa[ffa(x)]=y;
28             if((1<<j)<l) merge(st1+(1<<j),st2+(1<<j),l-(1<<j));
29             return;
30         }
31     }
32 }
33 
34 int main()
35 {
36     int n,m;
37     scanf("%d%d",&n,&m);
38     int cnt=0;
39     for(int j=0;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) 
40     {
41         num[i][j]=++cnt;
42         if(j!=0) son[cnt][0]=num[i][j-1],son[cnt][1]=num[i+(1<<j-1)][j-1];
43     }
44     for(int i=1;i<=cnt;i++) fa[i]=i;
45     for(int i=1;i<=m;i++)
46     {
47         int l1,r1,l2,r2;
48         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
49         merge(l1,l2,r1-l1+1);
50     }
51     for(int j=18;j>0;j--)
52     {
53         for(int i=1;i<=n;i++) if(num[i][j])
54         {
55             if(ffa(num[i][j])!=num[i][j])
56             {
57                 int x=num[i][j],y=ffa(num[i][j]);
58                 if(ffa(son[x][0])!=ffa(son[y][0])) fa[ffa(son[x][0])]=son[y][0];
59                 if(ffa(son[x][1])!=ffa(son[y][1])) fa[ffa(son[x][1])]=son[y][1];
60             }
61         }
62     }
63     int ans=1,tot=0;
64     for(int i=1;i<=n;i++) if(ffa(num[i][0])==num[i][0])
65     {
66         tot++;
67         if(ans==1) ans=1LL*ans*9%Mod;
68         else ans=1LL*ans*10%Mod;
69     }
70     if(tot==1) ans=10;
71     printf("%d\n",ans);
72     return 0;
73 }
View Code

 

2017-04-27 15:02:37io

相關文章
相關標籤/搜索