Codeforces Round #780 (Div. 3)

B - Vlad and Candies

题意

给定一个数组,每次只能取最大的元素,要求每次取的相邻的元素不能相等,问能否取完

题解

我们知道,当最大值比最大值多2的时候,这个时候拿掉一个最大值,接下来就没得选了

当最大值比最大值的差距小于等于1的时候,我们可以这两个值轮流来拿,使得其依次变小,这时候我们就能同时使这些数来变小,到与其他数相同的时候我们还可以选择其他数来变小,这样循环下去,我们就能使所有的数一起变为0

Code

void solve(){
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n);
    reverse(a + 1, a + 1 + n);

    if(n == 1){
        if(a[1] == 1)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
        re;
    }
    if(a[1] - a[2] > 1)
        cout << "NO" << Endl;
    else
        cout << "YES" << endl;
}

C - Get an Even String

题意

给定一个字符串,从中删除最小的字符数量满足下列条件:

  • 字符串长度为偶数
  • 对于所有的奇数 i ( 1 ≤ i ≤ n − 1 ) i(1\leq i \leq n-1) i(1in1),满足 a i = a i + 1 a_i=a_{i+1} ai=ai+1

题解

考虑删除字符串后,剩余字符串满足条件的最长长度

遍历字符串,如果出现相同的字符,就删除中间的

Code

string ss;

void solve(){
    cin >> ss;
    set<char> s;

    int ans = 0;

    for(auto i : ss){
        if(s.count(i)){
            ans += s.size() - 1;
            s.clear();
        }
        else
            s.insert(i);
    }
    cout << ans + s.size() << endl;
}

D - Maximum Product Strikes Back

题意

给定一个长度为 n n n的数组 a a a,其中 a ( a b s ( a ) ≤ 2 ) a(abs(a)\leq 2) a(abs(a)2),你可以删除数组的前缀和后缀,使其剩余子数组的乘积最大

问该怎么删除,其中空数组的乘积定义为1

题解

我们知道,当数组元素中出现0的时候显然是0的,所以我们以0为分隔,看其中的数的乘积是不是能够最大

同时我们知道,偶数个负数乘起来才是正数,而又因为数组元素的绝对值是 小于等于2的,也就是说只有出现2的时候,或者偶数个-2的时候,乘积才会增加

那么我们回过头来看这个已经被拿出来的这个子串。

如果里面的乘积是正的,那么我们直接看是否能更新答案;如果里面的乘积是负数,那么我们从左边找到第一个负数,从右边找到第一个负数,分别看看以这个数为分割点的左右两边是不是能更新答案

为什么要选第一个负数呢,首先乘积是负数说明我们现在出现了奇数个负数,我们去掉一个负数就可以使乘积变为正数;其次,如果选择下一个奇数的负数,也就是第三个负数,那么会漏掉很多数,显然不如只去掉一个负数来的乘积大

比赛的时候就只考虑了分隔负数后的一半的方向qwq

参考:https://zhuanlan.zhihu.com/p/491307345

Code

int n;
int a[N];
ll ans;
PII ans_id;

int cnt_fu(int l, int r){
    int cnt = 0;
    for (int i = l; i <= r; i ++) 
        if(a[i] < 0)
            cnt++;
    return cnt;
}

void update(int l, int r){
    if(l > r)
        return;

    int two = 0;
    for (int i = l; i <= r; i ++){
        if(abs(a[i]) == 2)
            two++;
    }

    if(two > ans){
        ans_id = {l - 1, n - r};
        ans = two;
    }
}

void work(int l, int r){
    int fu = cnt_fu(l, r);
    if(fu % 2 == 0){
        update(l, r);
    }
    else{
        int id = l;
        while(a[id] >= 0)
            id++;
        update(l, id - 1);
        update(id + 1, r);
        id = r;
        while(a[id] >= 0)
            id--;
        update(l, id - 1);
        update(id + 1, r);
    }
}

void solve(){
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
    }

    int l = 0;
    int r = 0;

    ans = 0;
    ans_id = {0, n};

    for (int i = 1; i <= n; i++){
        if(a[i] == 0){
            work(l + 1, r);
            l = i;
        }
        r++;
    }
    work(l + 1, r);
    cout << ans_id.x << ' ' << ans_id.y << endl;
}

E - Matrix and Shifts

题意

给定一个n*n的01矩阵,可以多次执行下列四个操作

  • 将第一行放到最后一行下面
  • 将最后一行放到第一行上面
  • 将第一列放到最后一列后面
  • 将最后一列放到第一列前面

现在问经过多次操作后,和一个单位矩阵相比,最少可以有多少个不同的地方

题解

还是参考ygg:https://zhuanlan.zhihu.com/p/491307345

Code

int n;
char s[2010][2010];

void solve(){
    cin >> n;
    for (int i = 0; i < n; i++){
        cin >> s[i];
    }

    int summ = 0;

    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            if (s[i][j] == '1')
                summ++;
        }
    }

    int ans = 0;
    for (int j = 0; j < n; j++){
        int cnt = 0;

        for (int i = 0; i < n; i++){
            if (s[i][(i + j) % n] == '1')
                cnt++;
        }

        ans = max(cnt, ans);
    }

    cout << summ - ans + n - ans << endl;
}

F2 - Promising String (hard version)

还是参考ygg,写的太好了https://zhuanlan.zhihu.com/p/491307345

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#include <unordered_map>
#define ll long long
#define ull unsigned long long
#define re return
#define pb push_back
#define Endl "\n"
#define endl "\n"
#define x first
#define y second
#define all(x) (x).begin(),(x).end()

using namespace std;

using PII = pair<int, int>;

const int N = 5e5 + 10;
const int M = 1e5 + 10;
const int mod = 1000000007;
const int INF = 0x3f3f3f3f;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;
// +----

struct BIT
{
    int tr[N];

    int lb(int x){
        return x & -x;
    }

    void init(int n){
        for (int i = 0; i <= n + 2; i++){
            tr[i] = 0;
        }
    }

    void modify(int p, int v){
        for(; p < N; p += lb(p)){
            tr[p] += v;
        }
    }

    int query(int p){
        int res = 0;
        for(; p; p -= lb(p)){
            res += tr[p];
        }
        return res;
    }

    int query(int l, int r){
        return query(r) - query(l - 1);
    }
}tr[3];
int n;
string ss;
int a[N];
int s[N];

void solve(){
    cin >> n;
    cin >> ss;

    ss = ' ' + ss;
    s[0] = 0;

    int minn = 0;
    for (int i = 1; i <= n; i++){
        a[i] = (ss[i] == '+' ? -1 : 1);
        s[i] = s[i - 1] + a[i];
        minn = min(minn, s[i]);
    }
    // cout << minn << endl;

    for (int i = 0; i <= n; i++)
        s[i] += (-minn + 1);

    for (int i = 0; i < 3; i ++)
        tr[i].init(n + (-minn + 1));

    ll ans = 0;
    for (int i = 0; i <= n; i++){  // 前缀和思想,我们要用pre[0]来构造答案
        int m = s[i] % 3;
        ans += tr[m].query(s[i]);
        tr[m].modify(s[i], 1);
    }

    cout << ans << endl;
}

int main(){
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    T = 1;
    cin >> T;
    while(T--){
        solve();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值