Codeforces Round #617(div3) A-E2题解

Posted honey-cat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #617(div3) A-E2题解相关的知识,希望对你有一定的参考价值。

A. Array with Odd Sum

? 有n个数的数组a,询问它是否有一个奇数和。

  • 满足:索引 i != j 且 ai != aj,可进行操作: ai = aj
  • 思路:
    1. 数组中必须有奇数,才可以产生奇数和 -> 全为偶数 -> 不可以
    2. n为偶数,数组中至少存在一个偶数 - 全为奇数,但n是偶数 -> 不可以
    3. 首先判断不存在奇数和的两种情况即可
B. Food Buying

? 有s块钱,每次买东西花费x元,会获得x / 10的回报(向下取整)。询问当前s,可以消费的最大值。

  • 思路
    1. 首先,当s < 10,不会获得回报,只能消费s元
    2. 贪心:消费x,获得x / 10的回报 --> 每次消费的x均为不大于当前s的最大的10的倍数,同样,在s < 10时为最后一次消费
C. Yet Another Walking Robot

? 机器人开始位与(0,0),机器人的移动方式: L: x - 1; R x + 1; U: y + 1 D: y - 1;输入一串长为n,包含机器人移动命令的字符串,需要删除不必要的路径(最短),保证最后到达位置不变。若不能删除,输出-1;否则,输出删除的最短路径的左右端点索引

  • 思路

    1. 寻找最短的可删除子串l,r初始值为0,n + 1 -- 字符串可能会被全部删除,也可能一个字符都不删除

    2. 使用map,记录上一次到达某位置时的字符串索引值 + 1,某位置是否到达过;

    3. 模拟机器人运行,若机器人运行到之前到过的位置,判断当前索引 -> 之前同位置索引的差值是否小于当前r - l,更新l,r的值;

    4. 最后判断l,r的值是否改变,输出“-1” or l 和 r;

map<pair<int,int>,int> m;
map<pair<int,int>,bool> vis;
pair<int,int> poi;//位置 
string s;
cin >> t;
while(t--){
	m.clear(),vis.clear();
	poi.first = poi.second = 0;
	cin >> n >> s;
	l = 0,r = n + 1;
	m[poi] = 0;//初始位置标记 
	vis[poi] = true;
	for(int i=0;i<n;i++){
		if(s[i] == ‘L‘) --poi.first;
		else if(s[i] == ‘R‘) ++poi.first;
		else if(s[i] == ‘U‘) ++poi.second;
		else --poi.second;
		if(vis[poi]){
			if(i+1-m[poi] < (r-l)){ 
				r = i+1;
				l = m[poi]+1;//idx+1 - 上次到达位置 + 1 开始删除
			}
			m[poi] = i+1;
		}else{
			m[poi] = i+1;
			vis[poi] = true;	
		}	
	}
	if(l == 0 && r == n + 1) cout << "-1" << endl;
	else cout << l << ‘ ‘ << r << endl;
} 
D. Fight with Monsters

? n个怪物,每个怪物血量为hi,a和b的攻击力为a,b。a,b先对付第一个怪物,怪物受到攻击,血量 -= 相应攻击力,直到它死亡(hi <= 0)。然后,对付第二个、第三个...

? 给予怪物最后一击的人得一分,a先开始攻击且a攻击后可以跳过b继续攻击一次(最多跳k次),询问a的最大得分。

思路:

  1. 当怪物的血量 mod a + b 为0,看最后一轮时a需要多攻击几次(b / a上取整)

  2. 在怪物mod a + b后还存在正的血量,a尽可能的连击到怪物死亡(多攻击:剩余血量 / a 上取整 - 1次)

  3. 输入数据后,按照取模后的余数升序排列,贪心:排在前面的,尽可能多的由a击杀

	cin >> n >> a >> b >> k;
	vector<int> arr(n);
	for(int i=0;i<n;i++){
		cin >> arr[i];
		arr[i] %= (a + b); 
		if(!arr[i]) arr[i] = a + b;//最后一轮 
		arr[i] = ((arr[i] + a - 1) / a) - 1;// a b a增加的次数上取整
	}
	sort(arr.begin(),arr.end());
	for(int i = 0; i < n; i++){
		if(k < arr[i]) break;
		++ans;
		k -= arr[i]; 
	} 
	cout << ans;
E1. String Coloring (easy version)

? 一个由小字字母组成的字符串,所有元素均被涂上了黑色 or 白色,相邻且异色的字符可交换,字符串中的字符是否可以升序排列,如果可以,给出染色方案:0 1表示两种颜色

思路:

? 异色字符才可以交换,同色字符相对顺序不会发生改变 -- 即同色字符不递减。

贪心:s是否可分为两个不递减的子串

  • 使用c1,c2分别记录两个同色字符串的最大字符,遍历字符串,若s[i] >= c1,加入c1所在子串;若 s[i] >= c2,加入c2所在子串;若s[i] 小于 c1,c2则在同色子串中出现递减 --> "NO"
//greedy
int n;
string s,ans;
char  c1 ,c2;
int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n >> s;
	c1 = c2 = ‘a‘;
	ans = "";
	for(int i = 0; i < s.length(); i++){
		if(s[i] >= c1) c1 = s[i],ans += ‘0‘;//第一个子串,染色0 
		else if(s[i] >= c2) c2 = s[i],ans += ‘1‘;
		else{
			cout << "NO";
			return 0;
		}
	}
	cout << "YES" << endl << ans;
	return 0;
}
E2. String Coloring (hard version)

? 与E1相比,字符的染色种类更多。需要输出染色种类最少的方案。

思路:

  1. 最多26种染色,依然可以贪心,增加一个字符串数组存储当前各字符串的最大字符,对s[i],进行E1中相同的步骤,不同的是:标记当前s[i]是否可以加入现有的字符串中,若不可以则增加一个字符串(题目保证最多26种染色,有解。),增加一个ans数组,在选择过程中存储答案即可。
const int kN = 2e5 + 5;
int n,idx,ans[kN];
bool flag;
char c[27];
string s;
//26个字符,最多26种染色 
int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n >> s;
	for(int i = 1;i <= 26; i++) c[i] = ‘a‘;
	idx = 1;
	for(int i = 0; i < s.length(); i++){
		flag = true;
		for(int j = 1; j <= idx && flag; j++){
			if(s[i] >= c[j]){
				c[j] = s[i];
				ans[i] = j;
				flag = false; 
			}
		}
		if(flag){
			c[++idx] = s[i];
			ans[i] = idx;
		}
	}
	cout << idx << endl ;
	for(int i = 0; i < n; i++){
		if(i) cout << ‘ ‘;
		cout << ans[i];
	}
	return 0;
}

2.DP解法,待填......

以上是关于Codeforces Round #617(div3) A-E2题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3)

Codeforces Round #617 (Div. 3) A