AtCoder Beginner Contest 337

文章介绍了使用C++解决的三个问题:队列排序算法、格子上的最少操作使连续区域全为o、以及通过二进制判断变质果汁的最少朋友测试。展示了如何利用数组表示队列结构,以及动态规划和二进制编码在求解中的应用。
摘要由CSDN通过智能技术生成

前面两道阅读理解直接跳过。

C - Lining Up 2

大意

有 n人在排队。

给你一个长度为n的序列A来排列这些人。

A_i(1 \le i \le n) 表示以下信息:

  • 如果A_i = -1 ,则i排在队伍的最前面
  • 如果A_i \ne 1,则 i紧跟在A_i 后面

从前到后打印一行人的编号。

思路

设置数组X_i表示第i个人的后面是X_i,读入A_i时,如果不为-1,则令X_{A_i}=i

否则,确定队首

确定队首后,根据X数组推出队伍

代码

#include <iostream>
using namespace std;
const int N = 3e5 + 9;
int a[N], b[N];
int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int x; cin >> x;
        if (x == -1) b[1] = i;
        else a[x] = i;
    }
    int cur = b[1];
    for (int i = 2; i <= n; i++) {
        b[i] = a[cur];
        cur = b[i];
    }
    for (int i = 1; i <= n; i++) cout << b[i] << " ";

    return 0;
}

D - Cheating Gomoku Narabe

大意

给定h\times w的二维网格,格子上有 xo.三种之一。

问最少进行的操作数,使得网格有连续k(水平或垂直)个格子都是 o

操作为:将一个为.的格子改为o

思路

枚举这连续k个格子的左端点 ,然后往右的k个格子里,不能有x,然后对.的数量取个最小值。事先预处理一下关于x.数量的前缀和。(为了方便,可以将x设为极大值

水平计算一次后,旋转90度再计算一次即可。

代码

#include <iostream>
#include <vector>
#include <climits>
#include <unordered_map>
using namespace std;
vector<string> grid, T;
#define int long long

int solve(const vector<string>& grid, int k) {
    int h = grid.size();
    int w = grid[0].size();
    unordered_map<char, int> mp;
    mp['.'] = 1;
    mp['x'] = INT_MAX;
    mp['o'] = 0;
    vector<vector<int>> pref(h, vector<int>(w));
    int ans = INT_MAX;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (j == 0) pref[i][j] = mp[grid[i][j]];
            else pref[i][j] = pref[i][j - 1] + mp[grid[i][j]];
            if (j >= k - 1) {
                ans = min(ans, pref[i][j] - (j == k - 1 ? 0 : pref[i][j - k]));
            }
        }
    }
    return ans;
}


signed main() {
    int h, w, k;
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> h >> w >> k;
    for (int i = 0; i < h; i++) {
        string s;
        cin >> s;
        grid.push_back(s);
    }

    int ans = solve(grid, k);

    T.assign(w, string(h, 'w'));
    for (int i = 0; i < h; i++)
        for (int j = 0; j < w; j++) T[j][i] = grid[i][j];

    ans = min(ans, solve(T, k));
    cout << (ans < INT_MAX ? ans : -1) << endl;
    return 0;
}

E - Bad Juice

大意

n瓶果汁,其中有一瓶变质了,喝了变质的果汁会不舒服,但你不知道哪瓶变质了。

你需要找最少的朋友,然后给他们一些果汁喝。一瓶果汁可以给多个朋友喝,一个朋友也可以喝多瓶果汁

第二天,朋友们会告诉你他们是否不舒服,你需要据此找到变质的果汁。

思路

对果汁编号0n-1,考虑其二进制。对于坏的果汁x,我们需要确定x的二进制下,哪些数位是1。

把 0n-1中,所有二进制下第 i位为1的都给第i个朋友喝,如果它第二天肚子疼了,说明 x第 i为1。

需要\lceil \log_2 n\rceil个朋友来试毒。

代码

#include<iostream>
#include<vector>
using namespace std;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    int m = 0;
    while((1 << m) < n) m++;
    cout << m << endl;
    for(int i = 0; i < m; i++){
        vector<int> c;
        for(int j = 0; j < n; j++)
            if((j >> i) & 1) c.push_back(j);
        cout << c.size() << " ";
        for(auto x: c) cout << x + 1 << " ";
        cout << endl;
    }
    
    string s;
    cin >> s;

    int ans = 0;
    for(int i = 0; i < s.size(); i++)
        if(s[i] == '1') ans += (1 << i);
    cout << ans + 1 << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值