刷题记录:牛客NC51097Parity game

传送门:牛客

题目描述:

Alice 和 Bob 在玩一个游戏:他写一个由 00 和 11 组成的序列。Alice 选其中的一段(比如第 33 位到第 55 
位),问他这段里面有奇数个 11 还是偶数个 11。Bob 回答你的问题,然后 Alice 继续问。Alice 要检查 Bob 
的答案,指出在 Bob 的第几个回答一定有问题。有问题的意思就是存在一个 0101 序列满足这个回答前的所
有回答,而且不存在序列满足这个回答前的所有回答及这个回答。
输入:
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
输出:
3

emmm,不愧是当年CEOI的一道题,思维难度确实大,虽然最终的实现方法一点就通,但是很难想到

主要思路:

  1. 首先假设我们并不知道这是一道并查集的题目,看到这道题直接自闭好吧.我当时看了一遍根本就看不出这是一道并查集的题.题目似乎也很好懂,但是就是无从下手.如果你思考的时间不足一小时的话,建议继续思考,看看如何与并查集结合起来(缩减难度了属于是)
  2. 如果实在是想不出来的话,就继续看吧.首先我们观察这个每次给我们的答案和左右端点.我们思考一下,因为是01串,我们是不是可以拿一个前缀和来维护我们的序列,如果一个区间内的1的个数是欧式的话,是不是意味着我们的前缀和的差是偶数(即SUM[R]-SUM[L-1]为偶数),反之是奇数.我们再思考一下,SUM数组的差为偶数代表了什么,怎样的两个数相减最后的答案会是一个偶数-----当然是SUM[R]和SUM[L-1]的奇偶性相同了.反之则不同.[感觉有一种2-set的味道了]
  3. 我们搞懂了之前的操作之后那么一切都变得简单了,我们会发现这就是一道扩展域并查集的题目了,什么,不知道扩展域并查集,可以去做做这道题
  4. 对于这道题,我们就开1~nn+1~2*n的两倍的并查集即可前半部分用来储存和自己相同奇偶性的位置,后半部分用来存储和自己奇偶性不同的式子,并且每次都使用并查集存一下两个数之间的关系,假设两个数的奇偶性不同的话,就将每一个数放在对面的对立的并查集之间即可.然后判断的时候就是用并查集来判断一下是不是与当前的奇偶性矛盾即可,假设矛盾的话,就直接输出ans,然后退出就行
  5. 但是由于这道题的N十分的巨大,达到了1e9的规模,因此我们直接使用数组来存储我们的并查集显然是会爆内存的.但是根据我们的思路,我们发现我们的存储关系是和我们的左右端点有关的(也就是说和我们的N的大小是无关的),因此我们可以使用离散化的技巧来巧妙的优化.但是用过离散化的人都知道,离散化的代码量虽然好理解但是挺繁杂的.但是C++又为我们提供了Map这个STL,并且Map这个数据结构就是用离散化来储存的!!,也就是说我们可以使用Map来巧妙的过这道题.

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int n,m;
map<int,int>fa;
struct Node{
	int l,r;
	string zhaungtai;
}node[6000];
int find(int a) {
	if(a==fa[a]) return a;
	else return fa[a]=find(fa[a]);
}
int main() {
	n=read();m=read();
	fa.clear();int flag=0;
	for(int i=1;i<=m;i++) {
		node[i].l=read();node[i].r=read();cin>>node[i].zhaungtai;
		fa[node[i].l-1]=node[i].l-1;fa[node[i].l+n]=node[i].l+n;
		fa[node[i].r]=node[i].r;fa[node[i].r+n+1]=node[i].r+n+1;
	}
	for(int i=1;i<=m;i++) {
		int l=node[i].l,r=node[i].r;string zhuangtai=node[i].zhaungtai;
		l--;
		if(zhuangtai[0]=='e') {
			if(find(l+n+1)==find(r)) {
				printf("%d\n",i-1);
				flag=1;
				break;
			}else {
				fa[find(l)]=find(r);
				fa[find(l+n+1)]=find(r+n+1);
			}
		}else{
			if(find(l)==find(r)) {
				printf("%d\n",i-1);
				flag=1;
				break;
			}else {
				fa[find(l+n+1)]=find(r);
				fa[find(r+n+1)]=find(l);
			}
		}
	}
	if(flag==0) printf("%d\n",m);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值