• 小胖的奇遇——论玄学


    小胖的奇偶

    题目描述:

    huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列。
    huyichen选其中的一段(比如第3位到第5位),问他这段里面有奇数个1还是偶数个1。
    xuzhenyi回答你的问题,然后huyichen继续问。
    xuzhenyi有可能在撒谎。huyichen要检查xuzhenyi的答案,指出在xuzhenyi的第几个回答一定有问题。
    有问题的意思就是存在一个01序列满足这个回答前的所有回答,而且不存在序列满足包括这个回答在内的所有回答,也就是自相矛盾。

    输入格式:

    第1行一个整数,是这个01序列的长度(<=1000000000)
    第2行一个整数,是问题和答案的个数。
    第3行开始是问题和答案,
    每行先有两个整数,表示你询问的段的开始位置和结束位置。
     然后是xuzhenyi的回答。odd表示有奇数个1,even表示有偶数个1。 

    输出格式:

    输出一行,一个数X,表示存在一个01序列满足第1到第X个回答,
    但是不存在序列满足第1到第X+1个回答。如果所有回答都没问题,你就输出
    所有回答的个数。

    样例输入:

    10
    5
    1 2 even
    3 4 odd
    5 6 even
    1 6 even
    7 10 odd 
    

    样例输出:

    3 
    

    时间限制:1000ms
    空间限制:128MByte

    这个题目简单来说就是一个并查集的题目,当在x到y区间有even个1时,我们可以得出在0到x-1和0到y区间中的1的个数的奇偶性是相同的,同理若有odd个1,0到x-1和0到y区间的1的个数的奇偶性就是不同的;所以我们就可以将数组分为两个部分表示是否相同与是否不同,我们可以用一个比较大的mod保证两个区间不重合,但是一看,(这个01序列的长度(<=1000000000))就知道我们不能naive地AC,因为这个数组太大了根本开不下,但是我们可以猜出这个询问并不会这么多(玄学*1);所以这个时候我们就需要用到STL!之前看的题解的话大多都是用哈希表,但是根据玄学,我们猜出询问次数不会很多,所以,可以用map来解决这个神奇的问题。(顺便还向大佬请教了一下map的用法)

    #include<bits/stdc++.h>
    #define mod 1000000000
    using namespace std;
    map<int,int> f;
    int n,m,pos;
    string s;
    void st(int x){
    	if (f.count(x)==0) f[x]=x;
    }//这个函数用于判断次节点是否有初值,若没有则将它自己的父亲设定为自己;
    int find(int x){
    	if (x==f[x]) return f[x];
    	f[x]=find(f[x]);
    	return f[x];
    }
    bool same(int x,int y){
    	return find(x)==find(y);
    }
    void link(int x,int y){
    	f[find(x)]=find(y);
    }
    int main(){
    	cin>>n>>m;
    	pos=-1;
    	for (int k=1; k<=m; k++){
    		int x,y;
    		cin>>x>>y>>s;
    		if (pos!=-1) break;
    		st(x-1);st(y);st(x-1+mod);st(y+mod);
    		if (s[0]=='e'){
    			if (same(x-1,y+mod) || same(x-1+mod,y)){
    				pos=k;
    			}
    			link(x-1,y);
    			link(x-1+mod,y+mod);
    		}
    		else {
    			if (same(x-1,y) || same(x-1+mod,y+mod)){
    				pos=k;
    			}
    			link(x-1,y+mod);
    			link(x-1+mod,y);
    		}
    	}
    	if (pos!=-1)
    	cout<<pos-1<<endl;
    	else cout<<m<<endl;
    	return 0;
    }
    

    啊哈哈,你以为这样就AC了吗?naive!但是是不是觉得之前的推理很有道理?对啊!我也是怎么觉得的,但是这惨痛的分数告诉了我们这个冷酷的事实.

    没错,我也很想不通,改了又改,改了又改。最终,还是去求助大佬了。听了大佬的思路。woc,这和我的思路不是一样的吗?(玄学*2),唯一不同的一点就是,他的区间分别是0~x和0~y+1,而我的思路是0~x-1和0~y(玄学*3),于是我带着试一试的思路试了一试(玄学*4)。

    #include<bits/stdc++.h>
    #define mod 1000000006
    using namespace std;
    map<int,int> f;
    int n,m,pos;
    string s;
    void st(int x){
    	if (f.count(x)==0) f[x]=x;
    }
    int find(int x){
    	if (x==f[x]) return f[x];
    	f[x]=find(f[x]);
    	return f[x];
    }
    bool same(int x,int y){
    	return find(x)==find(y);
    }
    void link(int x,int y){
    	f[find(x)]=find(y);
    }
    int main(){
    	cin>>n>>m;
    	pos=-1;
    	for (int k=1; k<=m; k++){
    		int x,y;
    		cin>>x>>y>>s;
    		if (pos!=-1) break;
    		st(x);st(y+1);st(x+mod);st(y+1+mod);
    		if (s[0]=='e'){
    			if (same(x,y+1+mod) || same(x+mod,y+1)){
    				pos=k;
    			}
    			link(x,y+1);
    			link(x+mod,y+1+mod);
    		}
    		else {
    			if (same(x+mod,y+1+mod) || same(x,y+1)){
    				pos=k;
    			}
    			link(x,y+1+mod);
    			link(x+mod,y+1);
    		}
    	}
    	if (pos!=-1)
    	cout<<pos-1<<endl;
    	else cout<<m<<endl;
    	return 0;
    }

    呵呵呵呵,玄学玄学,社会社会,(玄学*5),嗯哼?我会说我很绝望吗?当然不会了。(woc明天居然还有考试我当然绝望了!太tm绝望了。)

    made by cain-

  • 相关阅读:
    PAT-乙级-1034. 有理数四则运算(20)
    PAT-乙级-1033. 旧键盘打字(20)
    PAT-乙级-1032. 挖掘机技术哪家强(20)
    PAT-乙级-1031. 查验身份证(15)
    PAT-乙级-1030. *完美数列(25)
    PAT-乙级-1029. 旧键盘(20)
    PAT-乙级-1028. 人口普查(20)
    PAT-乙级-1027. 打印沙漏(20)
    PAT-乙级-1026. 程序运行时间(15)
    PAT-乙级-1025. 反转链表 (25)
  • 原文地址:https://www.cnblogs.com/cain-/p/7295759.html
Copyright © 2020-2023  润新知