破解

来源:互联网 发布:sql显示列名无效 编辑:程序博客网 时间:2024/04/20 11:35

Description

这里写图片描述

Input

第一行,一个整数 T 表示一共 T 组数据。
每组数据第一行,两个整数NM,分别表示密码串长度和区间个数。
接下来 M 行,第 i 行两个整数Li,Ri表示一个区间[Li,Ri]

Output

每组数据一行,一个整数表示所有的可能,答案对(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%的数据,N,M10
对于60%的数据,N10000000,M20
对于100%的数据,N10000000,M100000,1LiRiN,T10

Hint

第一组数据:每个位置都可以单个修改,所以所有长度为 3  01 串都有可能,即23=8种可能。
第二组数据的四种可能如下:
1.不操作:00000
2.选择区间[1,2]:11000
3.选择区间[4,5]:00011
4.先选择区间[1,2][4,5]:11011

solution

对于 30%的数据:
我们枚举那操作哪些区间然后暴力翻转,最后用一个 hash 判重
即可。
时间复杂度:O(N2M)
对于 60%的数据:
一个显然的结论:每次操作完的数列最后一定是 000...111...00
0...111...这种形式的,即一段连续的 0,再一段连续的 1,再一段连
续的 0...以此类推。我们把每一个 01 交界的位置成为关键位置,那
么最终的一个数列必然可以由它的关键位置表示,即关键位置集合一
样的数列是同一个数列。现在问题变为所有可能的关键位置集合的种
类数。
现在假设我们有 5 个区间[3,5),[2,4),[2,8),[4,8),[2,13)
假设现在选择[2,4),[4,8),[3,5),那么最终的序列是[0,1,0,0,1,1,1,0,...],关键位置集合为2,3,5,8。注意到一个结论,如
果我选择的区间端点出现了奇数次那么这个端点最终就是一个关键
位置,偶数次就不是。正确性比较显然,一个区间的端点第一次出现,
必然是关键位置,下一次出现会将其取反,使它变回非关键位置。
有了上述结论之后,问题就变得简单了,我们枚举操作那些区间
就可以统计答案了。
时间复杂度:O(2M)
对于 100%的数据:
有了上面的结论,我们可以更方便的处理问题。考虑转化成图论
模型来处理,对于一个区间[L,R)我们连从LR连一条无向边。现
在要对每条边赋值为 0/1,每个点的权值是所有与它相连的边权和,
要求最后有多少种不同的点权方案。这样做的好处是,我们可以独立
计算每一个联通块的方案,最后将它们乘起来就是答案。
至于计算联通块的内的方案数,这里又有一个比较容易想到的结
论:最终的方案数为 2
n1n 是联通块的点数。证明如下:
假如现在我们已经有一个大小为 n 的联通块了,现在连了(u,v)
v 点从联通块外连到联通块上,那么(u,v)这条边取 0/1 都是一种
可能方案,我们的新联通块方案数就是老方案数2,所以是 2n+1
再假如现在连了(u,v),而且 u,v 属于同一联通块,那么不管这条
边取 0 或取 1,我都可以通过翻转其他的边表示出新的方案,所以方
案数不变。
综上所述,大小为 n 的联通块最终的方案数为 2n1
设原图有 m 个结点和 k 个联通块,每个联通块大小为 m1,m2,m3...mk。那么最终答案为:
2m112m21...2mk1=2mk
时间复杂度: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.
1 0