Codeforces Round 908 (Div. 2)补题

Secret Sport

题目大意:两个人进行比赛,每场比赛只有一名玩家获胜,当一名玩家在一局比赛中赢x场后,这局比赛就结束了,当有玩家赢了y局比赛后,游戏结束。现在游戏结束了,我们知道每场得胜负情况,但是不知道最终的胜者是谁,请根据每场比赛的情况判断是否有胜者,以及胜者是谁。

思路:本题看似麻烦,但是实际上获胜的人一定是最后一场比赛的胜者。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		string s;
		cin>>s;
		cout<<*s.rbegin()<<endl;
	}
}

Two Out of Three

题目大意:给定一个序列a,我们要由此得到序列b,序列b满足以下三个条件中的两个:
1.存在i,j,ai=aj,bi=1,bj=2;

2.存在i,j,ai=aj,bi=1,bj=3;

3.存在i,j,ai=aj,bi=2,bj=3.

如果存在就打印b数组,否则打印-1。

思路:我们考虑,当a中有若干个数相等时,这些位置对应的b能有几种情况,如果这些位置一旦即有1,2,又有1,3,那么自然满足了第三个条件,有2,3,与题目要求的只满足两个条件不符。所以当有一类若干个相等的数的时候,只能满足一个条件,所以我们的解决方法就是,先查每类数有多少个,对于多于一个的,我们从中挑两个去满足条件就可。剩下的位置都赋为1。

#include<bits/stdc++.h>
using namespace std;
int a[200010];
map<int,int>mp;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		int c=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			mp[a[i]]++;
		}
		for(auto it:mp)
		{
			if(it.second>1) c++;
		}
		if(c<2) printf("-1\n");
		else
		{
			int flag=3;
			for(int i=1;i<=n;i++)
			{
				if(mp[a[i]]>1&&flag>1) 
				{
					printf("%d ",flag);
					flag--;
					mp[a[i]]=1;
				}
				else printf("1 ");
			}
			printf("\n");
		}
		mp.clear();
	}
}

Anonymous Informant

题目大意:我们给定b[]数组,已知b[]数组是由a[]数组进行k次如下操作得到的:
1.选一个下标x满足,ax=x

2.将数组周期性的向左移动x位。

问这样的a数组是否存在,如果存在打印“YES”,否则打印“NO”。

思路:我们每次选定x,将数组移动x位后,会发现被选中的数被移到了末尾,那么我们只要从b[]的末尾开始看,倒着往回移,如果能够移动k次,那么就说明存在a[]数组,如果不能移动k次那么就说明不存在a[],另外,要考虑到,如果我们一旦进行了n次移动,数组至少被循环了一次,既然可以循环,那么就一定存在满足要求的a[],所以我们逆操作的次数op=min(n,k);但是我们再考虑一下 ,如果要实际去移动数组的话,每次移动的时间复杂度是O(n),n的范围是到2e5的,所以不能真的移动,否则会超时,那么该怎么办呢,可以发现,我们每次关注的都是最后一个数,那么我们只需要用一个变量存一下每次移动完最后一个数的下标即可。至于更新,last-=a[last],当last<=0时,last+=n,由此问题全部解决。

#include<bits/stdc++.h>
using namespace std;
int a[200010];
int n,k,cnt;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		int op=min(n,k);
		int flag=1;
		cnt=0;
		int last=n;
		for(int i=0;i<op;i++)//未必要真的移动
		{
			if(a[last]>n)
			{
				flag=0;
				break;
			}
			last=last-a[last];
			if(last<=0) last += n;
		}
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
}

Neutral Tonality

题目大意:给定两个数组a[],b[],我们可以以任意顺序将b中的数插到a[]中,要使得到的数组的最长上升子序列的长度最小。

思路:a[]中已经产生的最长上升子序列我们自然是无法改变,那么我们就要尽可能地使新插入的数不产生上升序列,那么我们可以将b[]从大到小排序,然后用归并排序的思路(或者说双指针)插入,先插入大的。

#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		vector<int>a(n+10),b(m+10),tmp;
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
		}
		for(int i=0;i<m;i++)
		{
			scanf("%d",&b[i]);
		}
		sort(b.begin(),b.end(),cmp);//从大到小排
		int i=0,j=0;
		while(i<n&&j<m)
		{
			if(a[i]<b[j]) 
			{
				while(b[j]>a[i]&&j<m)
				{
					tmp.push_back(b[j]);
					j++;
				}
			}
			else if(a[i]>b[j])
			{
				while(a[i]>b[j]&&i<n) 
				{
					tmp.push_back(a[i]);
					i++;
				}
			}
			else
			{
				while(a[i]==b[j]&&i<n&&j<m)
				{
					tmp.push_back(a[i]);
					tmp.push_back(b[j]);
					i++,j++;
				}
			}
		}
		while(i<n) tmp.push_back(a[i++]);
		while(j<m) tmp.push_back(b[j++]);
		for(auto it:tmp) printf("%d ",it);
		printf("\n");
	}
}

当然下面这样写也可:

#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		vector<int>a(n+10),b(m+10),tmp;
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
		}
		for(int i=0;i<m;i++)
		{
			scanf("%d",&b[i]);
		}
		sort(b.begin(),b.end(),cmp);//从大到小排
		int i=0,j=0;
		while(i<n&&j<m)
		{
			if(a[i]<b[j]) 
			{
					tmp.push_back(b[j]);
					j++;
			}
			else if(a[i]>b[j])
			{
					tmp.push_back(a[i]);
					i++;
			}
			else
			{
					tmp.push_back(a[i]);
					tmp.push_back(b[j]);
					i++,j++;
			}
		}
		while(i<n) tmp.push_back(a[i++]);
		while(j<m) tmp.push_back(b[j++]);
		for(auto it:tmp) printf("%d ",it);
		printf("\n");
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值