你和一个朋友在玩一个游戏:他写一个由0和1组成的序列。
你选其中的一段(比如第3位到第5位),问他这段里面有奇数个1
还是偶数个1。你的朋友回答你的问题,然后你继续问。
你的朋友有可能在撒谎。你要检查他的答案,指出在他的第几个回答一定有问题。
有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列
满足这个回答前的所有回答及这个回答。
inout:
输入有多组数据。
每组数据的第1行一个整数,是这个01序列的长度(<=1000000000)
第2行一个整数,是问题和答案的个数。
第3行开始是问题和答案,
每行先有两个整数,表示你询问的段的开始位置和结束位置。
然后是你朋友的回答。odd表示有奇数个1,even表示有偶数个1。
输入文件以-1结束。
output:
每组测试数据输出一行,一个数X,表示存在一个01序列满足第1到第X个回答,
但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出
所有回答的个数。
input:
10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd
10
5
1 2 even
1 4 even
2 4 odd
1 10 even
3 10 even
-1
output:
3
5
分析:此题的大概思路是HASH+并查集,但是巧妙的是加上一个对立面(block),就是把两个结果映射在不同地方。
【参考程序】:
#include<iostream>
#include<string>
using namespace std;
const int hashmax=6000;
const int block=10000;
int hash[20000],father[20000];
int len,n,ans;
int hash_make(int num)
{
int pos=num%hashmax;
while (hash[pos]!=-1 && hash[pos]!=num)
pos=(pos+1)%hashmax;
hash[pos]=num;
return pos;
}
int Find(int x)
{
/*int root=x;
while (father[root]!=root) root=father[root];
while (root!=x)
{
int temp=father[x];
father[x]=root;
x=temp;
}
return root;*/
if (father[x]!=x) return Find(father[x]);
else return x;
}
void Union(int x,int y)
{
int p=Find(x),q=Find(y);
if (p!=q) father[p]=q;
}
int main()
{
string st;int i;
while (cin>>len,len!=-1)
{
cin>>n;
for (i=0;i<20000;i++) father[i]=i;
memset(hash,0xFF,sizeof(hash));
int a,b;
for (i=1;i<=n;i++)
{
cin>>a>>b>>st;
bool EVEN=(st=="even");
a=hash_make(a-1);
b=hash_make(b);
if (EVEN)
{//如果为偶,因为第一次我们全部是不同集合,那么a肯定和b的对立面是一个集合
if (Find(a)==Find(b+block)) break;
Union(a,b);
Union(a+block,b+block);
}
else
{
if (Find(a)==Find(b)) break;
Union(a+block,b);
Union(a,b+block);
}
}
ans=i-1;
for (++i;i<=n;i++)
cin>>a>>b>>st;
cout<<ans<<endl;
}
return 0;
}