Loading

24-2-28 个人赛




A - Grandma Laura and Apples

难度: ⭐⭐(⭐)

题目大意

小莫在市集卖苹果, 苹果的价格是p (p一定是偶数); 现在有n个顾客前来买苹果, 并且每次会买当前苹果数量的一半, 如果当前苹果数量是奇数, 那么小莫会再赠送顾客半个苹果; 给出的n组输入, 如果是"half", 则说明小莫没有赠送苹果; 如果是"halfplus", 说明小莫赠送了该顾客半个苹果; 请问小莫卖完所有苹果后的收益是多少;

解题思路

由题意得, 小莫手上的苹果会一直保持整数; 我们要从后往前推算总苹果数是多少; 最后苹果数量为cnt = 0, 如果是"halfplus", 则说明顾客购买之前苹果数量是奇数, 也就是cnt * 2 + 1; 如果是"half", 则是偶数, 也就是cnt * 2, 那么根据数量很容易得知顾客付了多少钱; 可以用dfs实现从后往前推算;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, cnt = 0, res = 0;
string s;
int p[N];
void dfs(int u){
    if(u < 1) return;
    string s;
    cin >> s;
    dfs(u - 1);
    if(s == "half"){
        cnt *= 2;
        res += cnt / 2 * m;
    }
    else if(s == "halfplus"){
        cnt = cnt * 2 + 1;
        res += cnt / 2 * m + m / 2; 
    }
}
signed main(){
    cin >> n >> m;
    dfs(n);
    cout << res;
	return 0;
}




B - Alice, Bob, Two Teams

难度: ⭐⭐

题目大意

现在有n个物品, 每个物品都有各自的价值Ai, 然后给出一个长度为n字符串, 将这些物品划分给小莫和安姐, 如果第i个字符是'A', 说明第i个物品属于安姐, 如果是'B', 则属于小莫; 现在小莫有一次操作机会, 她可以选择该字符串的一段前缀或者后缀, 然后把一段的字符翻转('A'变成'B','B'变成'A'); 请问小莫该如何选择可以让自己物品价值和最大;

解题思路

本题打一下暴力就行, 遍历前缀和后缀, 记录当前翻转后的情况, 记录最大值即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
string s;
int p[N];
signed main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> p[i];
    cin >> s;
    for(int i = 0; i < s.size(); i++){
        if(s[i] == 'B') res += p[i + 1];
    }
    int maxn = res, cnt = res;
    for(int i = 0; i < s.size(); i++){
        if(s[i] == 'A') cnt += p[i + 1];
        else cnt -= p[i + 1];
        maxn = max(cnt, maxn);
    }
    cnt = res;
    for(int i = s.size(); i >= 0; i--){
        if(s[i] == 'A') cnt += p[i + 1];
        else cnt -= p[i + 1];
        maxn = max(cnt, maxn);
    }
    cout << maxn;
	return 0;
}




C - Takahashi Gets Lost

难度: ⭐⭐⭐

题目大意

给定一个矩阵, 该矩阵由陆地和海洋组成, 小莫位于某个陆地上, 并且进行了n次移动; 给定这n次移动每次的方向; 请问有多少个可以满足条件的陆地;

解题思路

用bfs遍历即可; 状态表示除了坐标外, 还要表面下一步是第几步; 记录所有走完的个数即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k, res;
string s;
char g[510][510];
struct node{
    int x, y, id;
};
queue<node> q;
void bfs(){
    while(q.size()){
        auto t = q.front();
        q.pop();
        int x = t.x, y = t.y;
        if(t.id == s.size()){
            res++;
            continue;
        }
        if(s[t.id] == 'L'){
            if(y - 1 >= 1 && g[x][y - 1] == '.'){
                q.push({x, y - 1, t.id + 1});
            }
        }
        else if(s[t.id] == 'R'){
            if(y + 1 <= m && g[x][y + 1] == '.'){
                q.push({x, y + 1, t.id + 1});
            }
        }
        else if(s[t.id] == 'U'){
            if(x - 1 >= 1 && g[x - 1][y] == '.'){
                q.push({x - 1, y, t.id + 1});
            }
        }
        else if(s[t.id] == 'D'){
            if(x + 1 <= n && g[x + 1][y] == '.'){
                q.push({x + 1, y, t.id + 1});
            }
        }
    }
}
signed main(){
    cin >> n >> m >> k;
    cin >> s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cin >> g[i][j];
            if(g[i][j] == '.'){
                q.push({i, j, 0});
            }
        }
    }
    bfs();
    cout << res;
	return 0;
}




D - Epic Transformation

难度: ⭐⭐⭐

题目大意

现有一个长度为n的数组, 我们可以从中挑选出两个不同的数, 然后把他们从数组中删去; 该操作可以做无限次; 请问操作完后该数组的长度最短是多少;

解题思路

我们可以把这个题抽象成要把数组中满足条件的数两两匹配; 并且要优先和当前出现次数最多的数匹配; 我们可以把该数组规整一下; 比如原数组为1 2 1 3 1 2, 规整后为1 1 1 2 2 3; 按出现次数从大到小排列; 然后我们要从中切一刀, 将左边和右边的数组上下堆叠起来, 这样就实现了优先和出现次数最多的两两匹配, 并且还能保证两个数字之间不同; 但是要注意, 这一刀不能从出现次数最多的数字块中切, 因为那样会导致匹配时会有两个相同的数字;
其实再往后推我们会发现一个公式, 如果出现次数最多的数字的数量x大于等于n / 2, 那么直接让其他数字都和他匹配即可, 也就是2 * x - n; 相反如果小于n / 2, 那么按照上面的切法, 如果n是偶数, 那么一定可以让左边和右边的长度相等, 也就是0; 如果是奇数, 那就会多出一个, 也就是1;
注意: 至于怎么让map按第二关键字排序, 我们可以把map里的数据都挪到vector里面, 然后对vector进行自定义排序即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
string s;
int p[N], f[N];
vector<PII> v;
map<int, int> mp;
bool cmp(PII a, PII b){
    return a.second > b.second;
}
signed main(){
    IOS;
    int t;
    cin >> t;
    while(t--){
        cin >> n;
        int res = n;
        mp.clear();
        v.clear();
        for(int i = 1; i <= n; i++){
            cin >> p[i];
            mp[p[i]]++;
        }
        for(auto t : mp){
            v.push_back(t);
        }
        int idx = 0;
        sort(v.begin(), v.end(), cmp);
        for(auto t : v){
            for(int i = 1; i <= t.second; i++){
                f[++idx] = t.first;
            }
        }
        for(int i = 2; i <= n; i++){
            if(f[i] == f[1]) continue;
            res = min(res, abs(n - 2 * (i - 1)));
        }
        cout << res << endl;
    }
	return 0;
}




E - Rating Compression

难度: ⭐⭐⭐⭐

题目大意

给定长度为n的数组, 现在可以对其进行k压缩, 即对每个长度为k的区间, 取出其中的最小值组成的新数组, 新数组的长度即为n - k + 1; 如果一个长度为n的数组由1~n n个数字组成, 那么这就是一个全数组; 请问k取那些值时压缩后的数组是全数组;

解题思路

这题感觉语言表述不太清楚; 首先考虑两个特例, 当k = 1时得到的数组就是数组本身, 很容易判断其是否是全数组; 当k = n时得到的数组就是原数组中的最小值, 判断其是否为1即可; 而剩下的我们需要O(n)的来解决, 那么可以想到用递推来求; 当1 < k < n时, 数字1必须出现在开头或者结尾, 否则就一定会在压缩数组中出现两次; 处理完数字1后的数字2也是同理;
举个例子, 当k = n - 1时, 压缩数组长度为2; 我们只要保证数字1出现在开头或者结尾, 并且数组中存在数字2即可; 然后当k = n - 2时, 也要满足上面的条件, 并且同时2也要出现删去数字1后数组的开头或者结尾, 并且数组中还要有一个3; 综上所述, 这是一个可以递推的过程, 一旦某个k不满足了, 那么再往后的k也都不会满足; 又因为特定数字只会出现在数组两端, 所以可以用双指针来控制数组的长度; 细节还是看代码吧;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 3e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m;
int p[N], cnt[N], res[N];
signed main(){
    IOS;
	int t;
    cin >> t;
	while (t--) {
        cin >> n;
        for(int i = 1; i <= n; i++){
            res[i] = 0;
            cnt[i] = 0;
        }
        for(int i = 1; i <= n; i++){
            cin >> p[i];
            cnt[p[i]]++;
        }
        bool f = true;
        for(int i = 1; i <= n; i++){
            if(!cnt[i]){
                f = false;
                break;
            }
        }
        if(f) res[1] = 1;
        if(cnt[1]) res[n] = 1;
        int l = 1, r = n;
        int idx = 1;
        while(l < r){
            if((p[l] == idx || p[r] == idx) && (cnt[idx] - 1) == 0 && cnt[idx + 1]){
                if(p[l] == idx) l++;
                if(p[r] == idx) r--;
                res[n - idx] = 1;
                cnt[idx] --;
                idx++;
            }
            else break;
        }
        for(int i = 1; i <= n; i++){
            cout << res[i];
        }
        cout << endl;
	}
	return 0;
}
posted @ 2024-02-28 22:44  mostimali  阅读(2)  评论(0编辑  收藏  举报