• 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解法,待填......

  • 相关阅读:
    利用线程制作简单定时器
    VScode小白简介
    WebService介绍及C/C++访问
    Redis的C++与JavaScript访问操作
    Redis的安装配置及简单集群部署
    解决npm被墙的问题
    【学习整理】第三章 使用字符串
    【学习整理】第四章 字典
    【学习整理】第二章 列表和元祖
    【学习整理】第一章 基础知识部分 常用函数 简单语法
  • 原文地址:https://www.cnblogs.com/honey-cat/p/12881316.html
Copyright © 2020-2023  润新知