• 【日记】12.29/【题解】CF Good Bye 2019


    12.29

    CF GoodBye 2019

    本年度最后一场比赛上紫,感谢无敌的cyy!

    A.Card Game

    题意:有1-n一共n张牌,两个人一开始各随机拿一些,每次出一张,谁点数大谁就拿走两张,谁先没牌就输,问谁赢。

    思路:拥有最大的那张牌的人赢。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    const int M=1e5+20,P=1e9+7;
    struct Task{
    	int n,k1,k2;
    	void init(){
    		scanf("%d%d%d",&n,&k1,&k2);
    		int mx1=0,mx2=0;
    		for(int i=1;i<=k1;++i){
    			int c;
    			scanf("%d",&c);
    			mx1=max(mx1,c);
    		}	
    		for(int i=1;i<=k2;++i){
    			int c;
    			scanf("%d",&c);
    			mx2=max(mx2,c);
    		}	
    		if (mx1>mx2)
    			printf("YES
    ");
    		else
    			printf("NO
    ");
    	}
    	void run(){
    		init();
    	}
    }t;
    int main(){
    	int T;
    	scanf("%d",&T);
    	for(int i=1;i<=T;++i)
    		t.run();
    	return 0;
    }
    

    B.Interesting Subarray

    题意:如果一个array满足max(a)-min(a)>=array中元素个数,那么称这个array是interesting的,现在问给定一个array,是否存在一个非空子串array。

    思路:可以想到,如果相邻两个差值>=2,那么这两个就是interesting的。如果所有的相邻两个差值都<=1,那么整个都不存在interesting的子array。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    const int M=2e5+20,P=1e9+7;
    struct Task{
    	int n,a[M];
    	void init(){
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i)
    			scanf("%d",&a[i]);
    	}
    	void run(){
    		init();
    		for(int i=2;i<=n;++i)
    			if (abs(a[i]-a[i-1])>=2){
    				printf("YES
    %d %d
    ",i-1,i);
    				return ;
    			}
    		printf("NO
    ");
    	}
    }t;
    int main(){
    	int T;
    	scanf("%d",&T);
    	for(int i=1;i<=T;++i)
    		t.run();
    	return 0;
    }
    

    C.Make Good

    题意:若一串数的和=异或和的两倍,那么这一串数是good的。现要求增加不超过3个数,使其变成good的。

    思路:这个题思路很简单……记和是s,异或和是xs,那么首先加xs,就变成了s+xs, 0,之后再加s+xs,即可。

    我的思路是首先把s搞成100000000的形式,同时保证异或和的位数=s的位数-1,之后把s中那些对应在异或和里为1的再搞成1即可,其实很复杂。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    #define db(x) cout<<#x<<":"<<x<<endl;
    const int M=2e5+20,P=1e9+7;
    struct Task{
    	int n;
    	LL sump=0,sumx=0;
    	void init(){
    		scanf("%d",&n);
    		sump=sumx=0;
    		for(int i=1;i<=n;++i){
    			int c;
    			scanf("%d",&c);
    			sump+=c,sumx^=c;
    		}
    	}
    	int get_max(LL a){
    		int p=0;
    		while(a>=(1LL<<p))
    			++p;
    		return p;
    	}
    	void run(){
    		init();
    		if (sump==0){
    			printf("0
    
    ");
    			return;
    		}
    		LL o1=0,o2=0;
    		int ca1=get_max(sump),ca2=get_max(sumx);
    		o1=(1LL<<ca1)-sump;
    		sump+=o1,sumx^=o1;
    		ca1=get_max(sump),ca2=get_max(sumx);
    		if (ca1==ca2)
    			o1+=(1LL<<ca1)+(1LL<<(ca1-1)),sump+=(1LL<<ca1)+(1LL<<(ca1-1)),sumx^=((1LL<<ca1)+(1LL<<(ca1-1))),ca1+=2;
    		else if (ca1>ca2+1)
    			o1+=(1LL<<(ca1-1)),sump+=(1LL<<(ca1-1)),sumx^=(1LL<<(ca1-1)),ca1+=1;
    		printf("3
    ");
    		printf("%lld ",o1);
    		for(int i=ca1-2;i>=2;--i)
    			if ((sumx>>(i-1))&1)
    				o2+=(1LL<<(i-1));
    		printf("%lld %lld
    ",o2,o2);
    	}
    }t;
    int main(){
    	int T;
    	scanf("%d",&T);
    	for(int i=1;i<=T;++i)
    		t.run();
    	return 0;
    }
    

    D.Strange Device

    题意:有一台诡异机器,对于一个n个数的序列(没有相同的数),每次你输入k个不同的位置,它返回这k个位置上的数中第m大的。现在要求用不超过n次询问,找出m的值。

    思路:这个题相当傻。样例已经暗示了做法。只考虑k+1个数,依次mask所有数,答案一定是m个大数和k+1-m个小数。

    比如说,12345678,m=5,那么输出结果为:66666555。如果m=3,那么结果为44433333。

    找到规律了吧?

    #include<bits/stdc++.h>
    using namespace std;
    map<int,int> mp;
    int main(){
    	int n,k;
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k+1;++i){
    		printf("?");
    		for(int j=1;j<=k+1;++j)
    			if (j!=i)
    				printf(" %d",j);
    		putchar('
    ');
    		cout.flush();
    		int s1,s2;
    		cin>>s1>>s2;
    		++mp[s2];
    	}
    	map<int,int>::iterator it=mp.begin();
    	int val1=it->first,num1=it->second;
    	++it;
    	int val2=it->first;
    	if (val1<val2)
    		printf("! %d
    ",it->second);
    	else
    		printf("! %d
    ",num1);
    	cout.flush();
    	return 0;
    }
    

    E.Divide Points

    题意:有n个不同的点,要求分成A和B两个集合,使得集合内点对之间的距离集合,与集合间点对之间的距离集合没有交集。

    思路:cyy教我的……首先考虑既然是黑白染色,那么联想到x+y的奇偶性。事实上,将x+y为奇数划分到A,x+y为偶数划分到B即可。这样集合内部点对距离(差的平方和)一定是偶数,而集合间点对距离一定是奇数,这样就保证了开根之后的距离一定不相同。接下来考虑x+y全为奇数或全为偶数。事实上旋转坐标系即可,就类似于切比雪夫距离和曼哈顿距离转化。见代码。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define mid ((l+r)>>1)
    const int M=1e3+20,P=1e9+7;
    struct Point{
    	int x,y;
    	Point(int a=0,int b=0):x(a),y(b){}
    };
    struct Task{
    	int n;
    	Point a[M];
    	void init(){
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i)
    			scanf("%d%d",&a[i].x,&a[i].y);
    	}
    	void run(){
    		init();
    		while(1){
    			int ou=0,ji=0;
    			for(int i=1;i<=n;++i)
    				if ((a[i].x+a[i].y)%2==0)
    					++ou;
    				else
    					++ji;
    			if (ou!=n&&ou!=0){
    				printf("%d
    ",ou);
    				bool kong=false;
    				for(int i=1;i<=n;++i){
    					if (kong)
    						putchar(' ');
    					if ((a[i].x+a[i].y)%2==0)
    						printf("%d",i),kong=true;
    				}
    				putchar('
    ');
    				return;
    			}
    			else{
    				if (ji==n)
    					for(int i=1;i<=n;++i)
    						a[i].y+=1;
    				for(int i=1;i<=n;++i){
    					int cax=a[i].x,cay=a[i].y;
    					a[i].x=(cax+cay)/2,a[i].y=(cax-cay)/2;
    				}
    			}
    		}
    	}
    }t;
    int main(){
    	t.run();
    	return 0;
    }
    
  • 相关阅读:
    数据结构与算法
    ROS 机器人技术
    我常用的 VSCode C:C++ 插件!
    Ubuntu 常用的录屏、截图、Gif 软件!
    从 0 开始机器学习
    Word 设置页码从指定页开始的详细步骤!
    Ubuntu16.04 更新 ruby-2.6!
    配置 Git 不用每次 push 都输入密码!
    解决 rubygems.org 无法访问的问题!
    PHP 反序列化漏洞入门学习笔记
  • 原文地址:https://www.cnblogs.com/diorvh/p/12121358.html
Copyright © 2020-2023  润新知