Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3)

A - Array with Odd Sum

思路:有奇偶数同时存在YES,只有奇数是n是奇数为YES,否则NO

#include<bits/stdc++.h>
#define MAXN 2005
using namespace std;
int n,t;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		bool flag1 = false,flag2 = false;
		int tmp;
		for(int i = 1; i<= n;++i)
		{
			scanf("%d",&tmp);
			if(tmp&1)
				flag1 = true;
			else
				flag2 = true;
		}
		if((flag1 && flag2) || (flag1 && (n&1)))
			printf("YES\n");
		else
			printf("NO\n");
		}
		return 0;
	}

B - Food Buying

思路:超过10元不断花10元就好

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,n;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ll ans = 0;
		while(n >= 10)
		{
			ans += n/10*10;
			n = n% 10 + n / 10;
		}
		ans += n;
		printf("%lld\n",ans);
	}
	return 0;
}

C - Yet Another Walking Robot

思路:受限取的一段LR和UD的数量分别相同将L看成1,R看成-1,U看成1,D看成-1,分别求LR,UD的前缀和,如果两个位置LR和UD的前缀和都相等,那么它们中间一段就满足条件,因为存在负数,先加上一个数让他们都变为正数,然后记sum = LR前缀和INF+UD前缀和INF,这样sum相等时两个前缀和就分别相等了,然后对于每个下标处的sum值算出上一个sum相等地方的位置就好

#include<bits/stdc++.h>
#define MAXN 200005
#define ll long long
using namespace std;
char s[MAXN];
int sum1[MAXN],sum2[MAXN],sum[MAXN];
unordered_map<ll,int> mp;
int t,n;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%s",&n,s+1);
		mp.clear();
		sum1[0] = sum2[0] = n+1;
		for(int i = 1;i <= n;++i)
		{
			sum1[i] = sum1[i-1],sum2[i] = sum2[i-1];
			if(s[i] == 'U')
				++sum2[i];
			else if(s[i] == 'D')
				--sum2[i];
			else if(s[i] == 'R')
				++sum1[i];
			else
				--sum1[i];
			sum[i] = 1ll*2*MAXN*sum1[i]+sum2[i];
		}
		sum[0] = 1ll*2*MAXN*sum1[0]+sum2[0];
		int ans = MAXN,id1,id2;
		
		for(int i = 0;i <= n;++i)
		{
			if(mp.count(sum[i]) && ans > (i-mp[sum[i]]))
			{
				ans = i-mp[sum[i]];
				id1 = i;
				id2 = mp[sum[i]];
			}
			mp[sum[i]] = i;
		}
		if(ans == MAXN)
			printf("-1\n");
		else
			printf("%d %d\n",id2+1,id1);
	}
	return 0;
}

D - Fight with Monsters

思路:直接算出每个怪兽处要得分得跳多少次,然后排个序就好

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int n,a,b,k,h[MAXN],v[MAXN];
int main()
{
	while(~scanf("%d%d%d%d",&n,&a,&b,&k))
	{
		for(int i = 1;i <= n;++i)
		{
			scanf("%d",&h[i]);
			h[i] %= (a+b);
			if(h[i] == 0)
				h[i] = a+b;
			v[i] = h[i]/a;
			if(h[i] % a == 0)
				--v[i];
		}
		sort(v+1,v+n+1);
		int id = 1;
		while(k >= v[id] && id <= n)
			k-=v[id],++id;
		printf("%d\n",id-1);
	}
	return 0;
}

E1 - String Coloring (easy version)

思路:直接见E2

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int n,vis[26][MAXN],pre[26][MAXN],ans[MAXN];
char s[MAXN];
inline int find(int id,int x)
{
	return x == pre[id][x] ? x : pre[id][x] = find(id,pre[id][x]);
}
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i = 0;i < 26;++i)
	{
		for(int j = 0;j <= n;++j)
			pre[i][j] = j;
	}
	int mx = 1;
	for(int i = 1;i <= n;++i)
	{
		int id = s[i] - 'a';
		ans[i] = find(id,0)+1;
		mx = max(mx,ans[i]);
		for(int j = 0;j < id;++j)
		{
			if(!vis[j][ans[i]])
			{
				vis[j][ans[i]] = 1;
				pre[j][ans[i]-1] = ans[i];
			}
		}
	}
	if(mx <= 2)
	{
		printf("YES\n");
		for(int i = 1;i <= n;++i)
			printf("%d",ans[i]-1);
	}
	else
		printf("NO");
	return 0;
}

E2 - String Coloring (hard version)

思路:很明显每个字母要和前面所有比他大的进行交换,即要和前面所有比他大的字母染的颜色不同(将这些字母的颜色集合称为S),很明显颜色标号越小越好,即染成S中未出现的最小标号,直接维护26个并查集,第i个并查集维护出’a’+i对应的集合S,而每一个数的父亲一开始为自身,当x被染色后,x-1的父亲变为x,然后每次查询相应并查集0的父亲即为0开始连续一段中最大的颜色编号,这个编号加一即为需要染成的颜色

赛后看了下别人的,似乎前面比它大的字母的颜色标号会刚好覆盖1 ~ mx,直接取mx+1就好

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int n,vis[26][MAXN],pre[26][MAXN],ans[MAXN];
char s[MAXN];
inline int find(int id,int x)
{
	return x == pre[id][x] ? x : pre[id][x] = find(id,pre[id][x]);
}
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i = 0;i < 26;++i)
	{
		for(int j = 0;j <= n;++j)
			pre[i][j] = j;
	}
	int mx = 1;
	for(int i = 1;i <= n;++i)
	{
		int id = s[i] - 'a';
		ans[i] = find(id,0)+1;
		mx = max(mx,ans[i]);
		for(int j = 0;j < id;++j)
		{
			if(!vis[j][ans[i]])
			{
				vis[j][ans[i]] = 1;
				pre[j][ans[i]-1] = ans[i];
			}
		}
	}
	printf("%d\n",mx);
	for(int i = 1;i <= n;++i)
		printf("%d ",ans[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值