JZOJ 4807 【NOIP2016提高A组五校联考3】破解

破解

题目大意

这里写图片描述
这里写图片描述

问:

这里写图片描述这里写图片描述

答案对 109 + 7 取模

题解

首先做差分。
每一位上的数变为和前面的那个数的异或值。做完差分后的数组每一种不同的情况都对应着原串的每一种不同的情况。
然后每个区间对应的操作只会改变查分数组的两个位置,分别为Li Ri + 1
对于每个区间,我们把Li Ri + 1 连一条无向边。
考虑连边。
如果一条边连接了两个不同的联通块,那么这个区间选将会导致当前全部方案都变成新的方案,所以此时答案翻倍(乘2)。如果两个点本来就处于同一个联通块内,那么很显然,连了等于没连,对答案没有影响,如此这般把每一条边都连上就可以算出答案了。
连边操作以及联通块的维护可以用并查集。

Code(Pascal)

const
    mo=1000000007;
var
    fa:array[0..300000] of int64;
    qq:array[0..300000,1..3] of int64;
    qz:array[0..120000,1..2] of int64;
    t,y,i,j,k,kk,l,n,m,o:longint;
    ans:int64;
procedure qsort(l,r:longint);
    var
        i,j,m:longint;
    begin
        i:=l;
        j:=r;
        m:=qq[(l+r) div 2,1];
        repeat
            while qq[i,1]<m do inc(i);
            while qq[j,1]>m do dec(j);
            if i<=j then
            begin
                qq[0]:=qq[i];
                qq[i]:=qq[j];
                qq[j]:=qq[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
function gf(o:longint):longint;
    begin
        if fa[o]=o then exit(o);
        fa[o]:=gf(fa[o]); 
        exit(fa[o]);
    end;
begin
    readln(t);
    for y:=1 to t do
    begin
        o:=0;
        readln(n,m);
        for i:=1 to m do
        begin
            readln(qz[i,1],qz[i,2]);
            inc(o);
            qq[o,1]:=qz[i,1];
            qq[o,2]:=i;
            qq[o,3]:=1;
            inc(o);
            qq[o,1]:=qz[i,2]+1;
            qq[o,2]:=i;
            qq[o,3]:=2;
        end;
        qsort(1,o);
        k:=0;
        kk:=0;
        for i:=1 to o do
        begin
            if k<>qq[i,1] then
            begin
                inc(kk);
                k:=qq[i,1];
            end;
            qz[qq[i,2],qq[i,3]]:=kk;
        end;
        j:=0;
        for i:=1 to kk do
        fa[i]:=i;
        for i:=1 to m do
        if gf(qz[i,1])<>gf(qz[i,2]) then
        begin
            inc(j);
            fa[fa[qz[i,1]]]:=fa[qz[i,2]];
        end;
        ans:=1;
        for i:=1 to j do
        ans:=(ans*2) mod mo;
        writeln(ans);
    end;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值