zoukankan      html  css  js  c++  java
  • 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

    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
    ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    集合set() 和 深浅copy
    Python 数据类型的操作——字典
    Python()- 面向对象
    面向对象的软件开发
    Python数据类型的操作——列表、元组
    Python 数据类型的操作——字符串
    Linux下386中断处理
    任务的休眠与唤醒
    Linux下SIGSTOP的特殊特征和实现
    内核线程对信号的处理策略
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5534822.html
Copyright © 2011-2022 走看看