zoukankan      html  css  js  c++  java
  • BZOJ4569: [Scoi2016]萌萌哒

    题解:智商题啊  最朴素的写法 就是对应区间每个元素并查集一下然后最后查询有多少集合统计答案即可 复杂度O(n*m) 显然不行 然后看了题解的启发 我们可以用倍增的思想去做  我们用logn个并查集去维护第i层的集合分布关系 然后递推到下面  且f[i,j]表示的含义为第i个元素长度为2^j这一段区间所属的集合 那么第f[i,j-1]=f[i,j] f[i+(1<<(j-1)),j-1]=f[i,j]+(1<<(j-1)) 然后统计答案即可

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=1e5+10;
    const double eps=1e-8;
    const int mod=1e9+7;
    #define ll long long
    using namespace std;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
    	ll x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    
    int f[21][MAXN],n,m,x,y,l,r;
    bool vis[MAXN];
    int LOG[MAXN];
    ll ksm(ll a,ll b){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=ans*a%mod;
    		a=a*a%mod;b=b>>1;
    	}
    	return ans;
    }
    int find1(int x,int id){
    	if(f[id][x]==x)return x;
    	else return f[id][x]=find1(f[id][x],id);
    }
    void merge(int id,int a,int b){
    	int t1=find1(a,id);int t2=find1(b,id);
    	if(t1!=t2){
    		f[id][t1]=t2;
    	}
    }
    int main(){
    	n=read();m=read();
    	inc(i,2,n)LOG[i]=LOG[i>>1]+1;
    	inc(i,0,20)inc(j,1,n)f[i][j]=j;
    	while(m--){
    		x=read();y=read();l=read();r=read();
    		int k=LOG[y-x+1];
    		merge(k,x,l);merge(k,(y-(1<<k)+1),(r-(1<<k)+1));
    	}
    	for(int i=20;i>=1;i--){
    		for(int j=1;j+(1<<i)-1<=n;j++){
    			int t1=find1(j,i);
    			merge(i-1,j,t1);merge(i-1,j+(1<<(i-1)),t1+(1<<(i-1)));
    		}
    	}
    	int cnt=0;
    	for(int i=1;i<=n;i++){
    		int t1=find1(i,0);
    		if(!vis[t1])cnt++,vis[t1]=1;
    	}
    	printf("%lld
    ",1LL*9*ksm(10,cnt-1)%mod);
    }
    

    4569: [Scoi2016]萌萌哒

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1516  Solved: 764
    [Submit][Status][Discuss]

    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

    4 2
    1 2 3 4
    3 3 3 3

    Sample Output

    90

    HINT

     
  • 相关阅读:
    C#操作数据库,将其查查出来的记录条数显示在winform窗体中的方法之一
    关于SQL配置管理器的服务无法启动的解决办法!
    测试随笔
    .net版ckeditor配置水印功能(转)
    vs2010安装路径解决不能修改的方法
    c#wiform中KeyDown事件
    C#winform程序自定义鼠标样式
    一条sql语句循环插入N条不同记录(转)
    winform降低功耗总结
    ILMerge合并程序
  • 原文地址:https://www.cnblogs.com/wang9897/p/9640139.html
Copyright © 2011-2022 走看看