[SCOI2016]萌萌噠
阿新 • • 發佈:2018-02-28
1=1 dig IT 技術 src -- while esp 結果
題目描述
一個長度為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,後者第二位與第五位不同。問滿足以上所有條件的數有多少個。
輸入輸出格式
輸入格式:
第一行兩個數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的結果即可。
輸入輸出樣例
輸入樣例#1:4 2 1 2 3 4 3 3 3 3輸出樣例#1:
90
正解:
首先想到對於相同的數可以放到一個集合裏,用並查集維護
有多少個集合(假設有cnt個集合)
那麽最後答案就是ans=9*(10^(cnt-1))%mod
證明:第一個位置數字可以為9種(不能為0)
第二個位置數字可以為10種(0-9)
第三個位置數字可以為10種(0-9)
.........
一共有cnt個位置,即ans;
但是暴力的話,很明顯會超時,怎們辦呢?
我們可以用st表維護。
某個區間看成一個節點,他的兩個兒子拼起來即為自身區間
(按照倍增的區間分法)
當進行合並的時候,我們對區間進行合並而不是點。
最後,我們按照區間長度從大到小依次考察每個區間,
如果他並不是一個獨立的區間,那麽我們就把他的限制
放給他的兒子,即合並操作,直到區間長度為1
到最後統計一下集合的個數就可以得出答案
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<string> 6 #include<cmath> 7 #define ll long long 8 #define DB double 9 #define inf 214748360000 10 #define mod 1000000007 11 using namespace std; 12 inline intView Coderead() 13 { 14 int x=0,w=1;char ch=getchar(); 15 while(!isdigit(ch)){if(ch==‘-‘) w=-1;ch=getchar();} 16 while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar(); 17 return x*w; 18 } 19 const int N=1e5+90; 20 int n,fa[N*18],m,cnt,ch[N*18][2]; 21 int f[N][18]; 22 int F(int x) 23 { 24 if(x==fa[x]) return x; 25 else return fa[x]=F(fa[x]); 26 } 27 void merge(int x,int y) 28 { 29 int fx=F(x),fy=F(y); 30 fa[fx]=fa[fy]=fx; 31 } 32 int main() 33 { 34 n=read();m=read(); 35 for(int j=0;(1<<j)<=n;++j) 36 for(int i=1;i+(1<<j)-1<=n;++i) 37 { 38 f[i][j]=++cnt;fa[cnt]=cnt; 39 if(j) 40 { 41 ch[cnt][0]=f[i][j-1]; 42 ch[cnt][1]=f[i+(1<<(j-1))][j-1]; 43 } 44 } 45 while(m--) 46 { 47 int l1,r1,l2,r2; 48 l1=read();r1=read();l2=read();r2=read(); 49 int j=log2(r2-l2+1); 50 merge(f[l1][j],f[l2][j]); 51 merge(f[r1-(1<<j)+1][j],f[r2-(1<<j)+1][j]); 52 } 53 for(int i=cnt;i>n;--i) 54 { 55 int t=F(i); 56 if(t!=i) 57 { 58 merge(ch[i][0],ch[t][0]); 59 merge(ch[i][1],ch[t][1]); 60 } 61 } 62 cnt=0; 63 for(int i=1;i<=n;++i) 64 cnt+=(F(i)==i); 65 int ans=9; 66 for(int i=1;i<=cnt-1;++i) 67 ans=1ll*ans*10%mod; 68 printf("%d",ans); 69 return 0; 70 }
走到懸崖處,想辦法,就有路了(搭個梯子??)。
[SCOI2016]萌萌噠