Description
Input
第一行,一个整数 T T 表示一共 T T 组数据。
每组数据第一行,两个整数N,MN,M,分别表示密码串长度和区间个数。
接下来 M M 行,第 i i 行两个整数Li,RiLi,Ri表示一个区间[Li,Ri][Li,Ri]。
Output
每组数据一行,一个整数表示所有的可能,答案对(109+7)(109+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≤10N,M≤10
对于60%60%的数据,N≤10000000,M≤20N≤10000000,M≤20
对于100%100%的数据,N≤10000000,M≤100000,1≤Li≤Ri≤N,T≤10N≤10000000,M≤100000,1≤Li≤Ri≤N,T≤10
Hint
第一组数据:每个位置都可以单个修改,所以所有长度为 3 3 的 01 01 串都有可能,即23=823=8种可能。
第二组数据的四种可能如下:
11.不操作:
22.选择区间
33.选择区间
44.先选择区间
solution
对于 30%30%的数据:
我们枚举那操作哪些区间然后暴力翻转,最后用一个 hashhash 判重
即可。
时间复杂度:O(N∗2M)O(N∗2M)
对于 60%60%的数据:
一个显然的结论:每次操作完的数列最后一定是 000...111...00000...111...00
0...111...0...111...这种形式的,即一段连续的 00,再一段连续的 ,再一段连
续的 0...0...以此类推。我们把每一个 0101 交界的位置成为关键位置,那
么最终的一个数列必然可以由它的关键位置表示,即关键位置集合一
样的数列是同一个数列。现在问题变为所有可能的关键位置集合的种
类数。
现在假设我们有 55 个区间
假设现在选择[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,82,3,5,8。注意到一个结论,如
果我选择的区间端点出现了奇数次那么这个端点最终就是一个关键
位置,偶数次就不是。正确性比较显然,一个区间的端点第一次出现,
必然是关键位置,下一次出现会将其取反,使它变回非关键位置。
有了上述结论之后,问题就变得简单了,我们枚举操作那些区间
就可以统计答案了。
时间复杂度:O(2M)O(2M)
对于 100%100%的数据:
有了上面的结论,我们可以更方便的处理问题。考虑转化成图论
模型来处理,对于一个区间[L,R)[L,R)我们连从LL到RR连一条无向边。现
在要对每条边赋值为 0/10/1,每个点的权值是所有与它相连的边权和,
要求最后有多少种不同的点权方案。这样做的好处是,我们可以独立
计算每一个联通块的方案,最后将它们乘起来就是答案。
至于计算联通块的内的方案数,这里又有一个比较容易想到的结
论:最终的方案数为 22
是联通块的点数。证明如下:
假如现在我们已经有一个大小为 nn 的联通块了,现在连了,
将 vv 点从联通块外连到联通块上,那么这条边取 0/10/1 都是一种
可能方案,我们的新联通块方案数就是老方案数∗2∗2,所以是 2n+12n+1
再假如现在连了(u,v)(u,v),而且 u,vu,v 属于同一联通块,那么不管这条
边取 00 或取 ,我都可以通过翻转其他的边表示出新的方案,所以方
案数不变。
综上所述,大小为 nn 的联通块最终的方案数为 。
设原图有 mm 个结点和 个联通块,每个联通块大小为 m1,m2,m3...mkm1,m2,m3...mk。那么最终答案为:
2m1−1∗2m2−1∗...∗2mk−1=2m−k2m1−1∗2m2−1∗...∗2mk−1=2m−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.

本文针对一组区间操作问题,探讨了不同规模数据下的解决方案。对于小规模数据,采用暴力方法;中等规模数据,利用关键位置理论减少计算复杂度;大规模数据,则通过图论模型和联通块概念高效求解。
1103

被折叠的 条评论
为什么被折叠?



