奇偶游戏
法一:带权并查集
分析:
通过分析题目,假设s[i]为前缀和数组,我们可以得到以下等效关系:
[l,r]内1的个数 <=> s[r]-s[l-1] <=> 若为奇数,则s[l],s[r]奇偶性不同,若为偶数则相同
因此我们可以用带权并查集来解决这个问题。
我们在用带权并查集时,是维护了一个相对关系,通过与根节点的距离来判断与根节点是否同类。
距离mod2=1则不同类,mod2=0则同类
我们设d[x]为x到px的距离。同时补充一个知识点,在mod2的情况下进行加法,就是进行不进位的加法,即异或运算。
接下来进行分类讨论
1.x,y是同一类
- px=py 则两者距离根节点的距离相加应该为偶数,在mod2的意义下,则应该是dx^dy=0,是无矛盾的,若为1则有矛盾
- px!=py 则d[px]+d[x]+d[y]=偶数,则在mod2的意义下,应该为d[px]d[x]d[y]=0,即d[px]=d[x]d[y]0;
2.x,y是不同类
- px=py 则两者距离根节点的距离相加应该为奇数,在mod2的意义下,则应该是dx^dy=1,是无矛盾的,若为0则有矛盾
- px!=py 则d[px]+d[x]+d[y]=奇数,则在mod2的意义下,应该为d[px]d[x]d[y]=1,即d[px]=d[x]d[y]1;
ACcode
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10;
int p[N],d[N];
unordered_map<int,int> mp;
int n,m;
int get(int x)
{
if(!mp.count(x)) mp[x]=++n;
return mp[x];
}
int find(int x) // 并查集
{
if (p[x] != x)
{
int root = find(p[x]);
d[x] ^=d[p[x]];
p[x]=root;
}
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
n=0;
for(int i=1;i<=N;i++) p[i]=i;
int res = m;
for(int i=1;i<=m;i++)
{
int a,b;
string type;
cin>>a>>b>>type;
a = get(a-1),b = get(b);
int pa = find(a),pb = find(b);
int t = 0;
if(type=="odd") t=1;
if(pa==pb)
{
if(d[a]^d[b]!=t)
{
res = i-1;
break;
}
}
else
{
p[pa]=pb;
d[pa]=d[a]^d[b]^t;
}
}
cout<<res<<endl;
return 0;
}
法二:扩展域
分析:
扩展域,利用的是一种枚举的思想,通过枚举所有条件的可能性,来推论是否有矛盾。
x->x为偶数 x+n->x为奇数
再一个集合中的所有条件是互相可推导的。
1.x,y是同类
- x,y必须奇偶性相同,因此我们需要判断,是否能从x+n推导出y,或者从y+n推导出x,若能,则矛盾。
- 若没找到,则将x,y放到同一个集合,x+n与y+n放到同一个集合
2.x,y是异类
- x,y必须奇偶性不相同,因此若能从x推出y,或x+n推出y+n则矛盾
- 若是无矛盾,则将x与y+n放到同一集合,将y+n与x放到同一集合
ACcode
#include<bits/stdc++.h>
using namespace std;
const int N = 4e4 + 10;
int p[N];
unordered_map<int,int> mp;
int n,m;
int get(int x)
{
if(!mp.count(x)) mp[x]=++n;
return mp[x];
}
int find(int x) // 并查集
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
int idx=N/2;
n=0;
for(int i=1;i<=N;i++) p[i]=i;
int res = m;
for(int i=1;i<=m;i++)
{
int a,b;
string type;
cin>>a>>b>>type;
a = get(a-1),b = get(b);
if(type=="even")
{
if(find(a+idx)==find(b))
{
res = i-1;
break;
}
p[find(a)]=p[find(b)];
p[find(a+idx)]=p[find(b+idx)];
}
else
{
if(find(a)==find(b))
{
res = i - 1;
break;
}
p[find(a+idx)]=p[find(b)];
p[find(b+idx)]=p[find(a)];
}
}
cout<<res<<endl;
return 0;
}

浙公网安备 33010602011771号