Codeforces Round 966 (Div. 3) (A-F)

题目链接

目录

A

B

C

D

E

F


A

首先转化为字符串存储,前两位必须是10。第三位到最后不能出现前导零,且转成数字之后需大于等于2。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;
void slove()
{
    string str; cin >> str;
    if(str.size() < 3 || (str[0] != '1' || str[1] != '0')) { cout << "NO" << endl; return; }
    else
    {
        int a = 0;
        for(int i = 2; i < str.size(); i++)
        {
            a *= 10;
            a += str[i] - '0';
            if(a == 0) { cout << "NO" << endl; return; }
        }
        if(a < 2) { cout << "NO" << endl; return; }
    }
    cout << "YES" << endl;
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while(t--) slove();
    return 0;
}

B

使用一个数组存储每个座位是否空位的情况:规定有人为1,空位为0。除了第一个人可以随便坐,后面所有人必须坐在左右两边数组值之和大于等于1的座位。(为了避免越界,简化代码,不特判边界情况,请将数组开大一点)

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;
void slove()
{
    int n; cin >> n;
    vector<int> a(n + 10, 0);
    bool flag = true;
    for(int i = 1; i <= n; i++)
    {
        int t; cin >> t;
        if(i != 1)
            if(a[t + 1] + a[t - 1] == 0) flag = false;
        a[t] = 1;
    }
    if(flag) cout << "YES" << endl;
    else cout << "NO" << endl;
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while(t--) slove();
    return 0;
}

C

首先预处理数组,将相同的元素的下标通过map映射到vector中。对于任意字符串,先判断长度是否和数组长度相同,然后同样也映射到vector中。遍历两个map,判断对应的下标元素是否相同

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
using ll = long long;
void slove()
{
    int n; cin >> n;
    vector<int> nums(n + 1, 0);
    map<int, vector<int>> hn;
    for(int i = 1; i <= n; i++)
    {
        cin >> nums[i];
        hn[nums[i]].push_back(i);
    }

    int m; cin >> m;
    while(m--)
    {
        map<char, vector<int> > hs;
        string s; cin >> s;
        if(s.size() != n) { cout << "NO" << endl; continue; }
        string str = " " + s;
        bool flag = true;
        
        for(int i = 1; i < str.size(); i++)
            hs[str[i]].push_back(i);
        
        for(auto& e : hs)
        {
            vector<int>& b = e.second;
            int c = nums[b[0]];
            for(int i = 1; i < b.size(); i++)
            {
                if(c != nums[b[i]]) {  flag = false; break; }
            }
        }
        for(auto& e : hn)
        {
            vector<int>& b = e.second;
            char c = str[b[0]];
            for(int i = 1; i < b.size(); i++)
            {
                if(c != str[b[i]]) {flag = false; break; }
            }
        }
        if(flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while(t--) slove();
    return 0;
}

D

选择一个区间之后,就不可再选择该区间中间的区间了。每次得到的分数是该区间的和,所以我们每次都尽可能选择靠近中间的区间。那么对于先选择最靠近中间的区间,然后往两端移动,得到的分数;和从两端往中间靠依次得到的分数是相同的。对于一个区间的和,利用前缀和处理。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
using ll = long long;
void slove()
{
    int n; cin >> n;
    vector<int> nums(n + 1, 0);
    vector<ll> pre(n + 1, 0);
    for(int i = 1; i <= n; i++)
    {
        cin >> nums[i];
        pre[i] = pre[i - 1] + nums[i];
    }
    string a; cin >> a;
    string str = " " + a;
    ll res = 0;
    for(int i = 1, j = n; i < j; i++, j--)
    {
        while(i < j && str[i] != 'L') i++;
        while(i < j && str[j] != 'R') j--;
        if(str[i] == 'L' && str[j] == 'R')
            res += pre[j] - pre[i - 1];
    }
    cout << res << endl;
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while(t--) slove();
    return 0;
}

E

尽可能将高的猩猩放在被小方格覆盖次数最多的单元格中。对于一个 k*k 的小方格,最多覆盖一个单元格 k*k 次。可以对于 n*m 的网格中的每一个单元格求出被 k*k 的小方格覆盖的次数,利用二维差分。使用大根堆存储,然后将数组降序排列,依次相乘即为答案。时间复杂度O(n*m) 

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
using ll = long long;

void slove()
{
    int n, m, k; cin >> n >> m >> k;
    int w; cin >> w;
    vector<vector<int>> cnt(n + 2, vector<int>(m + 2, 0));
    vector<int> a(w, 0);
    for(int i = 0; i < w; i++) cin >> a[i];
    sort(a.begin(), a.end(), greater<int>());
    
    for(int i = 1; i <= n - k + 1; i++)
        for(int j = 1; j <= m - k + 1; j++)
        {
            cnt[i][j]++;
            cnt[i + k][j]--;
            cnt[i][j + k]--;
            cnt[i + k][j + k]++;
        }
    
    vector<vector<int>> pre(n + 1, vector<int>(m + 1, 0));
    priority_queue<int, vector<int>> q;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + cnt[i][j];
            q.push(pre[i][j]);
        }
    }
    ll res = 0;
    for(int i = 0; i < w; i++)
    {
        res += (ll) q.top() * a[i];
        q.pop();
    }
    cout << res << endl;
    
}  

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while(t--) slove();
    return 0;
}

F

对于一个矩阵中的单元格染色,可能会造成行或列变满,从而加分。对于任意 n*m 矩阵,最多是全部染色,n*m 分。每一次加分都是行变满或者列变满导致的,可以动态规划求得任意一个矩阵,加分 [0, n*m] 的最小操作数。所以可以先预处理 n 个矩阵,val[i][j]:第 i 个矩阵分数为 j 所需的最小操作数。时间复杂度O(n*a*b)(a 和 b 为任意矩阵的长宽)

预处理好之后就可以转变为一个01背包的问题了:对于 n 个矩阵,每个矩阵选与不选,分数至少为 k ,最少操作数是多少。

集合:f[i][j]:从前 i 个矩阵中选择,分数至少为 j 的最小操作数。
对于第 i 个矩阵:

  1. 不选:f[i - 1][j]
  2. 选: f[i - 1][j - v] + val[i][v]
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;

void slove()
{
    int n, k; cin >> n >> k;
    vector<vector<int>> val(n + 1, vector<int>(k + 1, 1e9));
    for (int i = 1; i <= n; i++)
    {
        int x, y; cin >> x >> y;
        for (int a = 0; a <= x; a++)
        {
            for (int b = 0; b <= y && a + b <= k; b++)
            {
                val[i][a + b] = min(val[i][a + b], a * y + b * x - a * b);
            }
        }
    }
    vector<vector<int>> f(n + 1, vector<int>(k + 1, 1e9));

    f[0][0] = 0;
    
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= k; j++)
        {
            f[i][j] = f[i - 1][j];
            for (int v = 0; v <= j; v++)
                f[i][j] = min(f[i][j], f[i - 1][j - v] + val[i][v]);
        }

    int res = 1e9;
    for (int i = 1; i <= n; i++)
        res = min(res, f[i][k]);

    if (res == 1e9) res = -1;
    cout << res << endl;
    
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while (t--) slove();
    return 0;
}

Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值