【并查集】奇偶游戏

本文介绍了一种使用并查集解决奇偶游戏的方法。通过建立前缀和与区间和的关系,每次操作从r向l-1连边并根据输入确定边权,查询时进行路径压缩并累加边权。当数值范围较大时,可以采用离散化策略。给出的标程可供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【并查集】奇偶游戏

题目:

你和你的朋友玩一个游戏。你的朋友写下来一连串的0或者1。你选择一个连续的子序列然后问他,

这个子序列包含1的个数是奇数还是偶数。你的朋友回答完你的问题,接着你问下一个问题。

你怀疑你朋友的一些答案可能是错误的,你决定写一个程序来帮忙。程序将接受一系列你的

问题及你朋友的回答,程序的目的是找到第一个错误的回答i,也就是存在一个序列满足前i-1个问

题的答案,但是不满足前i个问题。
输入:

输入第一行有一个整数LL<=1000000000,是这个01序列的长度。第二行是一个整数N(N<=5000),

是问题及其答案的数目,接下来N行描述问题和答案。每一行包含一个问题和这个问题的答案:

两个整数(子序列的起始位置和结束位置)和一个单词‘even’或者‘odd,even’表示这

个子序列中的‘1’的个数是偶数,‘odd’则表示是奇数。
输出:

输出中只需输出一行一个整数X。表示存在一个01序列满足前面的X个问题,但是不存在一个01序列满

足前X+1个问题,如果存在一个序列满足所有问题,则输出N


首先想到的是暴力去枚举字符串的状态再逐一判断

这种方法不仅思路复杂,而且效率非常低

以下是正解(并查集)

我们首先要知道,l~r的区间的和如何表示

设有一个前缀和f

那么就可以表示为f[r]-f[l-1]

根据这个原理,我想到:

每次操作从r向l-1连一条边,并根据输入确定边权(奇为1,偶为0)

每次寻找父亲的同时压缩路径,累加边权

至于长度太大的处理方法,可以使用离散化

我看n比较小,于是只开了一个列表去存储

每次查询一个值的复杂度也不会太高

标程:(仅供参考,请勿抄袭)

var     b:array[0..10000]of longint;
        father:array[0..10000,1..2]of longint;
        l,n,i,j,x,y,x1,y1,x2,y2,k,ans:longint;
        st:string;
function lookfor(t:longint):longint;
var     i,x:longint;
begin
        x:=0;
        for i:=1 to b[0] do
        if b[i]=t then
        begin
                x:=i;
                break;
        end;
        if x<>0 then exit(x)
        else
        begin
                inc(b[0]);
                b[b[0]]:=t;
                exit(b[0]);
        end;
end;
function find(t:longint):longint;
begin
        k:=(k+father[t,2])mod 2;
        if father[t,1]=t then exit(t)
        else exit(find(father[t,1]));
end;
begin
        readln(l);
        readln(n);
        ans:=n;
        for i:=1 to 10000 do
        father[i,1]:=i;
        for i:=1 to n do
        begin
                readln(x,y,st);
                x1:=lookfor(x-1);
                y1:=lookfor(y);
                k:=0;
                x2:=find(x1);
                father[x1,1]:=x2;
                father[x1,2]:=k;
                k:=0;
                y2:=find(y1);
                father[y1,1]:=y2;
                father[y1,2]:=k;
                if x2<>y2 then
                begin
                        father[y2,1]:=x2;
                        if st=' even' then
                        father[y2,2]:=(father[y1,2]-father[x1,2]+2)mod 2
                        else
                        father[y2,2]:=(father[y1,2]-father[x1,2]+3)mod 2
                end
                else
                begin
                        if st=' even' then
                        begin
                                if(father[x1,2]<>father[y1,2]) then
                                begin
                                        ans:=i-1;
                                        break;
                                end
                        end
                        else
                                if(father[y1,2]-father[x1,2]+2)mod 2<>1 then
                                begin
                                        ans:=i-1;
                                        break;
                                end;

                end;
        end;
        writeln(ans);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值