题解 CHSEQ22 【Chef and Favourite Sequence】

题目链接

Solution Chef and Favourite Sequence

题目大意:给定一个长为\(n\)的全\(0\)序列,以及\(m\)个操作\([l,r]\),代表将区间\([l,r]\)翻转。问通过这\(m\)个操作可以生成多少种不同的序列

并查集,线性基


分析:

最终序列实际上就是选择的操作异或起来(把每个操作当做\([l,r]\)\(1\),其它为\(0\)的序列)

实际上有一些操作是可以被其他操作表示出来的,被表示出来的操作都是无用的。(实际上就是求这个线性空间的基)

设剩余操作有\(x\)个,那么答案为\(2^x\)

求线性基显然不能暴力求,考虑特殊性质,\(1\)是连续的

我们可以做一个差分,对\([l,r]\)的修改变成\(l,r+1\)两点的修改

那么可以用并查集来维护,每次合并\(l,r+1\),如果一个区间的端点\(l,r\)在同一集合说明它已经被表示出来了

如果一组操作有关显然会形成一个环,也就是说我们不需要考虑操作的顺序

#include <cstdio>
#include <cctype>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100,mod = 1e9 + 7;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
int f[maxn],n,m,ans;
inline int mul(int a,int b){return (1ll * a * b) % mod;}
inline int qpow(int a,int b){
	int res = 1,base = a;
	while(b){
		if(b & 1)res = mul(res,base);
		base = mul(base,base);
		b >>= 1;
	}
	return res;
}
inline int find(int x){
	return x == f[x] ? x : f[x] = find(f[x]);
}
inline void merge(int x,int y){
	x = find(x),y = find(y);
	f[x] = y;
}
int main(){
	n = read(),m = read();
	for(int i = 1;i <= n + 1;i++)f[i] = i;
	for(int l,r,i = 1;i <= m;i++){
		l = read(),r = read() + 1;
		if(find(l) == find(r))continue;
		merge(l,r),ans++;
	}
	printf("%d\n",qpow(2,ans));
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/13394143.html
今日推荐