Description
历经千辛万苦,ddddddpppppp 终于找到了IBN5100。 dp 事先了解到SERN 共有T 个密码,每个密码是一个长度为N 的01 串,他要利用IBN5100 的特殊功能破解SERN 的密码。 初始时,IBN5100 中的串每个位置都是0。 这台特殊的IBN5100 还提供了M 个区间[Li,Ri],每次操作是从给定区间中选 择其中一个区间[Li,Ri],将当前01 串[Li,Ri]的位置上的数字全部取反。 dp 可以执行上述操作任意次。为了破解出密码,dp 想知道这个01 串最多有多 少种可能。
由于答案可能很大,所以你只需要告诉 dp 模(10^9+7)后的答案即可。
注意:每次破解都是独立的。
Input
第一行,一个整数T 表示一共T 组数据。
每组数据第一行,两个整数N,M,分别表示密码串长度和区间个数。
接下来M 行,第i 行两个整数Li,Ri 表示一个区间[Li,Ri]。
Output
每组数据一行,一个整数表示所有的可能,答案对(10^9+7)取模。
Sample Input
2
3 3
1 1
2 2
3 3
5 2
1 2
4 5
Sample Output
8
4
Hint
【样例解释】
第一组数据:每个位置都可以单个修改,所以所有长度为3 的01 串都有可能,即2^3=8 种可能。
第二组数据的四种可能如下:
1.不操作:00000
2.选择区间[1,2]:11000
3.选择区间[4,5]:00011
4.先选择区间[1,2]再选择[4,5]:11011
【数据范围】
对于30%的数据,N,M ≤ 10
对于60%的数据,N ≤ 10000000 , M ≤ 20
对于100%的数据,N ≤ 10000000 , M ≤ 100000 ,1 ≤ Li ≤ Ri ≤ N , T≤ 10
题解:
这个题目很巧秒,显然如果区间与区间之间没有相互之间影响,那么答案就会是2^n次方,也就是每个区间有乘二的贡献,因为既然你相互不影响,那我这个区间就有反和不反两种情况,但既然会影响所以我们要想办法把本质不同的组合给筛选出来。
就是一个区间或者一个组合如果能被多个区间或者组合所取代,那么他们的本质就是一样的,所以我们只要乘一次二就可了,怎么筛选,用并查集连边判重就可以了。
代码:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<cstring> #define ll long long #define mod 1000000007; const int MAXN=10000010; using namespace std; int fa[MAXN],l[MAXN],r[MAXN],v[MAXN]; int n,m,t; int num=0; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void cl(){ memset(fa,0,sizeof(fa)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(v,0,sizeof(v)); } int main(){ scanf("%d",&t); while(t--){ cl(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&l[i],&r[i]);r[i]++; } for(int i=1;i<=n+3;i++) fa[i]=i; ll ans=1; for(int i=1;i<=m;i++){ int x=find(l[i]),y=find(r[i]); if(x==y) continue; ans*=2;ans%=mod; fa[x]=y; } printf("%lld ",ans); } }
…………