破解

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

Description

这里写图片描述

Input

第一行,一个整数 T  T 表示一共 T  T 组数据。
每组数据第一行,两个整数NMN,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,M10N,M≤10
对于60%60%的数据,N10000000,M20N≤10000000,M≤20
对于100%100%的数据,N10000000,M100000,1LiRiN,T10N≤10000000,M≤100000,1≤Li≤Ri≤N,T≤10

Hint

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

solution

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值