奇偶游戏(扩展域

# 题意

首先,小A写了一个由0和1组成的序列S,长度为N。

然后,小B向小A提出了M个问题。

在每个问题中,小B指定两个数 l 和 r,小A回答 S[l~r] 中有奇数个1还是偶数个1。

机智的小B发现小A有可能在撒谎。

例如,小A曾经回答过 S[1~3] 中有奇数个1, S[4~6] 中有偶数个1,现在又回答 S[1~6] 中有偶数个1,显然这是自相矛盾的。

请你帮助小B检查这M个答案,并指出在至少多少个回答之后可以确定小A一定在撒谎。

即求出一个最小的k,使得01序列S满足第1~k个回答,但不满足第1~k+1个回答。

# 题解

将每个给定的都看作是条件,同样用到前缀和,

x表示 l-1,y表示 r

1)如果有偶数个,合并xodd和yodd,xeven和yeven,说明x为奇数和y为奇数可以互相推出,x为偶和y为偶也可以互相推出。

2)如果有奇数个,那么合并xodd和yeven,xeven和yodd,说明x为奇数和y为偶数可以互相推出,x为偶和y为奇也可以互相推出。

自然满足传递性even都+N/2和odd加以区分,并且不会冲突

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e4+10,base=N/2;
 4 unordered_map<int,int>h;
 5 int fa[N];
 6 int n,m;
 7 int cnt;
 8 int find(int x){
 9     if(fa[x]!=x) fa[x]=find(fa[x]);
10     return fa[x];
11 }
12 int get(int x) {
13     if (h[x] == 0) h[x] = ++cnt;
14     return h[x];
15 }
16 int main(){
17     cin>>n>>m;
18     for(int i=0;i<=N;i++)
19         fa[i]=i;
20 
21     for(int i=1;i<=m;i++){
22         int l,r;
23         string op;
24         cin>>l>>r>>op;
25         l=get(l-1),r=get(r);
26 
27         int x_even=l+base,x_odd=l;
28         int y_even=r+base,y_odd=r;
29         if(op == "even"){
30             if(find(x_odd)==find(y_even)) {
31                 cout<< i - 1<<endl;
32                 return 0;
33             }
34             fa[find(x_even)]=find(y_even);
35             fa[find(x_odd)]=find(y_odd);
36         }
37         else {
38             if(find(x_odd)==find(y_odd)){
39                 cout<<i-1<<endl;
40                 return 0;
41             }
42             fa[find(x_odd)]=find(y_even);
43             fa[find(x_even)]=find(y_odd);
44         }
45     }
46     cout<<m<<endl;
47 }

猜你喜欢

转载自www.cnblogs.com/hhyx/p/12446499.html