破解

1 篇文章 0 订阅

Description

这里写图片描述

Input

第一行,一个整数  T    T   表示一共  T    T   组数据。
每组数据第一行,两个整数 NM 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,M10 N , M ≤ 10
对于 60% 60 % 的数据, N10000000,M20 N ≤ 10000000 , M ≤ 20
对于 100% 100 % 的数据, N10000000,M100000,1LiRiN,T10 N ≤ 10000000 , M ≤ 100000 , 1 ≤ L i ≤ R i ≤ N , T ≤ 10

Hint

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

solution

对于 30% 30 % 的数据:
我们枚举那操作哪些区间然后暴力翻转,最后用一个 hash h a s h 判重
即可。
时间复杂度: O(N2M) O ( N ∗ 2 M )
对于 60% 60 % 的数据:
一个显然的结论:每次操作完的数列最后一定是 000...111...00 000...111...00
0...111... 0...111... 这种形式的,即一段连续的 0 0 ,再一段连续的 1,再一段连
续的 0... 0... 以此类推。我们把每一个 01 01 交界的位置成为关键位置,那
么最终的一个数列必然可以由它的关键位置表示,即关键位置集合一
样的数列是同一个数列。现在问题变为所有可能的关键位置集合的种
类数。
现在假设我们有 5 5 个区间[3,5),[2,4),[2,8),[4,8),[2,13)
假设现在选择 [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
n1n 是联通块的点数。证明如下:
假如现在我们已经有一个大小为 n n 的联通块了,现在连了(u,v)
v v 点从联通块外连到联通块上,那么(u,v)这条边取 0/1 0 / 1 都是一种
可能方案,我们的新联通块方案数就是老方案数 2 ∗ 2 ,所以是 2n+1 2 n + 1
再假如现在连了 (u,v) ( u , v ) ,而且 u,v u , v 属于同一联通块,那么不管这条
边取 0 0 或取 1,我都可以通过翻转其他的边表示出新的方案,所以方
案数不变。
综上所述,大小为 n n 的联通块最终的方案数为 2n1
设原图有 m m 个结点和 k 个联通块,每个联通块大小为 m1,m2,m3...mk m 1 , m 2 , m 3 . . . m k 。那么最终答案为:
2m112m21...2mk1=2mk 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.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值