• 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;
    }
    

      

  • 相关阅读:
    李彦宏最新演讲:移动互联网的时代已经结束了
    表值函数 详解
    SQL中PIVOT 行列转换
    将WeX5部署到自己的Tomcat服务器上
    Cordova webapp实战开发:(2)认识一下Cordova
    Cordova webapp实战开发:(1)为什么选择 Cordova webapp?
    甲有5套房,不上班,靠收房租生活;乙有1套房,上班赚工资……(启示)
    Ubuntu 16.04下为Android编译OpenCV 3.1.0 Manager
    Dual Camera Info
    OpenCV 3.1
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5534822.html
Copyright © 2020-2023  润新知