1. 程式人生 > >bzoj 4569: [Scoi2016]萌萌噠

bzoj 4569: [Scoi2016]萌萌噠

stdin etc 有關 bits con clu include CP freopen

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

Solution

暴力做法就是把相同的合並在一起,最後答案只跟連通塊數量有關了

對於每一個限制,合並的復雜度是 \(O(n)\)
我們用倍增的思想,也就是 \(st\) 表的思想
假如在合並第 \(k\) 層,且 \(find(i)==find(j)\),說明 \(S[i,i+2^k-1]=S[j,j+2^k-1]\)
也說明第 \(k-1\) 層,\(find(i)==find(j),find(i+1<<(k-1))==find(j+(1<<(k-1)))\)
逐層遞推下去就可以得到我們要求的並查集了

#include<bits/stdc++.h>
using namespace std;
template<class T>void
gi(T &x){ int f;char c; for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1; for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f; } const int N=1e5+10,mod=1e9+7; int n,m,Log[N]; struct ST{ int fa[N]; inline
void init(){for(int i=1;i<=n;i++)fa[i]=i;} inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} inline void merge(int x,int y){fa[find(y)]=find(x);} }st[25]; int main(){ freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); cin>>n>>m; int l1,l2,r1,r2,len; for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1; for(int i=0;i<=Log[n];i++)st[i].init(); for(int i=1;i<=m;i++){ gi(l1);gi(r1);gi(l2);gi(r2);len=Log[r1-l1+1]; st[len].merge(l1,l2);st[len].merge(r1-(1<<len)+1,r2-(1<<len)+1); } for(int j=Log[n];j>=1;j--) for(int i=1;i+(1<<j)-1<=n;i++){ int k=st[j].find(i); if(i==k)continue; st[j-1].merge(i,k); st[j-1].merge(i+(1<<(j-1)),k+(1<<(j-1))); } int cnt=0; for(int i=1;i<=n;i++)if(st[0].find(i)==i)cnt++; int ans=9; for(int i=1;i<cnt;i++)ans=1ll*ans*10%mod; cout<<ans<<endl; return 0; }

bzoj 4569: [Scoi2016]萌萌噠