BZOJ4569: [Scoi2016]萌萌哒
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
1 2 3 4
3 3 3 3
3 3 3 3
Sample Output
90
好巧妙的思路,我心服口服了。
不难发现每一次操作等价于在两个区间内依次合并连通分量,如果暴力合并显然是O(NM)的。
怎么办呢?我们对序列建立ST表,这样就可以理解成有nlogn个点,合并时先合并大块,再递归合并小块。注意每一个点只参与一次合并,总时间复杂度仍为O(MlogN)。
不知道为什么按秩合并反而快一点。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘; return x*f; } typedef long long ll; const int maxn=100010; int n,m,A[maxn],pa[maxn*20],s[maxn*20],Log[maxn]; int id(int k,int x) {return k*n+x;} int findset(int x) {return pa[x]==x?x:findset(pa[x]);} void merge(int x,int y,int k) { int f1=findset(id(k,x)),f2=findset(id(k,y)); if(f1!=f2) { if(s[f1]>s[f2]) swap(f1,f2); pa[f1]=f2;if(s[f1]==s[f2]) s[f2]++; if(k) merge(x,y,k-1),merge(x+(1<<k-1),y+(1<<k-1),k-1); } } int main() { n=read();m=read(); for(int i=0;(1<<i)<=n;i++) rep(j,1,n) pa[id(i,j)]=id(i,j),s[id(i,j)]=1; Log[0]=-1;rep(i,1,n) Log[i]=Log[i>>1]+1; rep(i,1,m) { int a=read(),b=read(),c=read(),d=read(),k=Log[b-a+1]; merge(a,c,k);merge(b-(1<<k)+1,d-(1<<k)+1,k); } int cnt=0; rep(i,1,n) A[i]=findset(id(0,i)); sort(A+1,A+n+1); rep(i,1,n) if(A[i]!=A[i-1]) cnt++; if(cnt==1) puts("10"); else { ll ans=9; rep(i,1,cnt-1) (ans*=10)%=1000000007; printf("%lld\n",ans); } return 0; }
以上是关于BZOJ4569: [Scoi2016]萌萌哒的主要内容,如果未能解决你的问题,请参考以下文章