Description
Input
第一行,一个整数
T
T
表示一共
T
T
组数据。
每组数据第一行,两个整数
N,M
N
,
M
,分别表示密码串长度和区间个数。
接下来
M
M
行,第
i
i
行两个整数
Li,Ri
L
i
,
R
i
表示一个区间
[Li,Ri]
[
L
i
,
R
i
]
。
Output
每组数据一行,一个整数表示所有的可能,答案对 (109+7) ( 10 9 + 7 ) 取模
Sample Input
2
3 3
1 1
2 2
3 3
5 2
1 2
4 5
Sample Output
8
4
Data Constraint
对于
30%
30
%
的数据,
N,M≤10
N
,
M
≤
10
对于
60%
60
%
的数据,
N≤10000000,M≤20
N
≤
10000000
,
M
≤
20
对于
100%
100
%
的数据,
N≤10000000,M≤100000,1≤Li≤Ri≤N,T≤10
N
≤
10000000
,
M
≤
100000
,
1
≤
L
i
≤
R
i
≤
N
,
T
≤
10
Hint
第一组数据:每个位置都可以单个修改,所以所有长度为
3
3
的
01
01
串都有可能,即
23=8
2
3
=
8
种可能。
第二组数据的四种可能如下:
1
1
.不操作:
2
2
.选择区间
3
3
.选择区间
4
4
.先选择区间
solution
对于
30%
30
%
的数据:
我们枚举那操作哪些区间然后暴力翻转,最后用一个
hash
h
a
s
h
判重
即可。
时间复杂度:
O(N∗2M)
O
(
N
∗
2
M
)
对于
60%
60
%
的数据:
一个显然的结论:每次操作完的数列最后一定是
000...111...00
000...111...00
0...111...
0...111...
这种形式的,即一段连续的
0
0
,再一段连续的 ,再一段连
续的
0...
0...
以此类推。我们把每一个
01
01
交界的位置成为关键位置,那
么最终的一个数列必然可以由它的关键位置表示,即关键位置集合一
样的数列是同一个数列。现在问题变为所有可能的关键位置集合的种
类数。
现在假设我们有
5
5
个区间
假设现在选择
[2,4),[4,8),[3,5)
[
2
,
4
)
,
[
4
,
8
)
,
[
3
,
5
)
,那么最终的序列是
[0,1,0,0,1,1,1,0,...]
[
0
,
1
,
0
,
0
,
1
,
1
,
1
,
0
,
.
.
.
]
,关键位置集合为
2,3,5,8
2
,
3
,
5
,
8
。注意到一个结论,如
果我选择的区间端点出现了奇数次那么这个端点最终就是一个关键
位置,偶数次就不是。正确性比较显然,一个区间的端点第一次出现,
必然是关键位置,下一次出现会将其取反,使它变回非关键位置。
有了上述结论之后,问题就变得简单了,我们枚举操作那些区间
就可以统计答案了。
时间复杂度:
O(2M)
O
(
2
M
)
对于
100%
100
%
的数据:
有了上面的结论,我们可以更方便的处理问题。考虑转化成图论
模型来处理,对于一个区间
[L,R)
[
L
,
R
)
我们连从
L
L
到
R
R
连一条无向边。现
在要对每条边赋值为
0/1
0
/
1
,每个点的权值是所有与它相连的边权和,
要求最后有多少种不同的点权方案。这样做的好处是,我们可以独立
计算每一个联通块的方案,最后将它们乘起来就是答案。
至于计算联通块的内的方案数,这里又有一个比较容易想到的结
论:最终的方案数为
2
2
是联通块的点数。证明如下:
假如现在我们已经有一个大小为
n
n
的联通块了,现在连了,
将
v
v
点从联通块外连到联通块上,那么这条边取
0/1
0
/
1
都是一种
可能方案,我们的新联通块方案数就是老方案数
∗2
∗
2
,所以是
2n+1
2
n
+
1
再假如现在连了
(u,v)
(
u
,
v
)
,而且
u,v
u
,
v
属于同一联通块,那么不管这条
边取
0
0
或取 ,我都可以通过翻转其他的边表示出新的方案,所以方
案数不变。
综上所述,大小为
n
n
的联通块最终的方案数为 。
设原图有
m
m
个结点和 个联通块,每个联通块大小为
m1,m2,m3...mk
m
1
,
m
2
,
m
3
.
.
.
m
k
。那么最终答案为:
2m1−1∗2m2−1∗...∗2mk−1=2m−k
2
m
1
−
1
∗
2
m
2
−
1
∗
.
.
.
∗
2
m
k
−
1
=
2
m
−
k
时间复杂度:
O(M)
O
(
M
)
code
const maxn=10000005;
mo=1000000007;
var x,y,tt,ans,tot,t,fax,fay,i,m,n:longint;
vis:array[0..maxn] of boolean;
yy,next,dt:array[0..200005] of longint;
g:array[0..maxn] of longint;
procedure make(x,y:longint);
begin
inc(tot);
yy[tot]:=y;
next[tot]:=g[x];
g[x]:=tot;
end;
procedure dfs(x:longint);
var y,i:longint;
begin
vis[x]:=true;
i:=g[x];
inc(ans);
while i<>0 do begin
y:=yy[i];
if not vis[y] then dfs(y);
i:=next[i];
end;
end;
function ni(x:longint):int64;
var ans,y:int64;
begin
y:=2;
ans:=1;
while x<>0 do begin
if x mod 2=1 then ans:=ans*y mod mo;
y:=y*y mod mo;
x:=x div 2;
end;
exit(ans);
end;
begin
readln(t);
for t:=1 to t do begin
readln(n,m);ans:=0;
fillchar(next,sizeof(next),0);
fillchar(g,sizeof(g),0);tot:=0;
fillchar(yy,sizeof(yy),0);
fillchar(vis,sizeof(vis),false);
tt:=0;
for i:=1 to m do begin
readln(x,y);
x:=x-1;
inc(tt);dt[tt]:=x;
inc(tt);dt[tt]:=y;
make(x,y);
make(y,x);
end;
for i:=1 to tt do begin
if not vis[dt[i]] then begin
dfs(dt[i]);
dec(ans);
end;
end;
writeln(ni(ans));
end;
end.