Codeforces Round #814 (Div. 2)(A~D)

A. Chip Game

在一个n*m大小的棋盘上,从左下角移动到右上角,每次只能向一个方向移动奇数个格子(向右或向上),最后不能移动的输,B先手,问最后谁赢。

思路:每次移动奇数,那所有奇数的性质相同,偶数性质相同。易得出n和m奇偶性质相同时,T赢,反之则B赢。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
const int mod=1e9+7;
int t,n,m;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>m;
		if(n%2==m%2) std::cout<<"Tonya"<<'\n';
		else std::cout<<"Burenka"<<'\n';
	}
	return 0;
}

B. Mathematical Circus

 给出n和k,将1~n分为两两一组,并规定其中某个数为a,某个数为b,满足(a+k)*b为4的倍数,问是否存在满足条件的分组方式,有则输出分组方式。

思路:满足是4的倍数,要么两个因数各有2,要么其中一个数为4的倍数,首先k为0一定不行,因为最小的1,2组合需要加入大数才能满足条件;若不为0,则判断是否满足整除4的条件,即交换a和b的值。易得分组为相邻两数两两互组。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
typedef std::pair<int,int>PII;
const int N=1e5+5;
const int mod=1e9+7;
int t,n,k;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>k;
		if(k&1){
			std::cout<<"YES"<<'\n';
			for(int i=1;i<=n;i+=2){
				std::cout<<i<<' '<<i+1<<'\n';
			}
		}
		else{
			bool flag=true;
			std::vector<PII>ans;
			for(int i=1;i<=n;i+=2){
				if((k+i+1)%4==0){
					ans.push_back({i+1,i});
				}
				else if((i+1)%4==0){
					ans.push_back({i,i+1});
				}
				else{
					flag=false;
					break;
				}
			}
			std::cout<<(flag?"YES":"NO")<<'\n';
			if(flag){
				for(int i=0;i<n/2;i++){
					std::cout<<ans[i].first<<' '<<ans[i].second<<'\n';
				}
			}
		}
	}
	return 0;
}

 C. Fighting Tournament

给出n个数,从左侧依次拿出两个数比较,大的留下,小的置于队尾,若某个数大于比较的数,则赢一次,给出比较轮数,q次询问,每次回答每个数赢得次数。

思路: 观察可以发现,一个数会赢的条件是没有遇到比自己大的数;若是整个数组中最大的数,则在开始比较后全赢;若是该数前面存在比它大的数,则一直为0。根据这个条件,分类讨论即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
typedef std::pair<int,int>PII;
const int N=1e5+5;
const int mod=1e9+7;
int t,n,q,id,k;
int a[N],cnt[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>q;
		memset(cnt,0,sizeof(cnt));
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		int pos=1,max=a[1];
		for(int i=2;i<=n;i++){
			if(a[i]<max) cnt[i]=0;
			else{
				cnt[pos]=i;
				pos=i;
				max=a[i];
			}
		}
		cnt[pos]=-1;
		while(q--){
			std::cin>>id>>k;
			if(cnt[id]==0){
				std::cout<<0<<'\n';
			}
			else if(cnt[id]==-1){
				if(k>=std::max(1,id-1)) std::cout<<k-std::max(0,id-1-1)<<'\n';
				else std::cout<<0<<'\n';
			}
			else{
				int max=cnt[id]-1;
				if(k<max){
					if(k<std::max(1,id-1)) std::cout<<0<<'\n';
					else std::cout<<k-std::max(0,id-1-1)<<'\n';
				}
				else{
					std::cout<<max-std::max(0,id-1-1)-1<<'\n';
				}
			}
		}
	}
	return 0;
}

os:WA麻了

D2. Burenka and Traditions (hard version)

给出n个数,每次选择一个x,将一个区间异或x,问最少的操作次数,使得数组全为0。

思路:大佬的思路显然最多的操作数是n,把每一个数都亦或上自己即可。为了尽可能减少操作次数,显而易见的是对于一段连续的相同的数比如2222,我们也可以通过一次操作把他变为0。但是本质其实是对于一个新的数,我们要判断前面的数载操作后能否顺便把这个数也变成0。

我们需要的是在操作一个新数前的所有的后缀异或和。比如一串序列a, b, c。我们在操作a,b后并保证ab都变成0的情况下,c可能的取值是c,b^c,a^b^c,模拟一下即可。那么所有的后缀就是b和a^b,我们用set来维护所有的后缀,然后在枚举新数的时候判断是否出现在后缀里即可。

AC Code:

#include <bits/stdc++.h>

int t,n;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		std::vector<int>a(n+1,0);
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		int res=0;
		std::set<int>s;
		s.insert(0);
		int suf=0;
		for(int i=1;i<=n;i++){
        	if(s.count(a[i]^suf)||a[i]==0) s.clear(),suf=0;
        	else res++,s.insert(suf),suf^=a[i];
    	}
    	std::cout<<res<<'\n';
	}
	return 0;
}

os:这思维太顶了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值