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

 
原文地址:https://www.cnblogs.com/wang9897/p/9640139.html