CodeCraft-22 and Codeforces Round #795 (Div. 2)

目录

A. Beat The Odds

B. Shoe Shuffling

C. Sum of Substrings

D. Max GEQ Sum


A. Beat The Odds

A. Beat The Odds

思路:如果数组中即存在奇数,又存在偶数,则必定存在两数之和为奇数的情况,所以,数列必须全奇数或者全偶数,我们的目的,找到数组中奇数的个数,与偶数的个数,取 min 输出即可

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;

const int N = 2e5+10;

int T;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

void solve()
{
    int n;
    int a[N];
    string s;

    scanf("%d", &n);

    int x, resa = 0, resb = 0;
    for(int i = 0; i < n; i ++ )
    {
        scanf("%d", &x);
        if(x%2) resa ++;
        else resb ++;
    }

    cout << min(resa, resb) << endl;

    return;
}

int main()
{
    scanf("%d", &T);

    while(T -- )
        solve();

    return 0;
}

B. Shoe Shuffling

B. Shoe Shuffling

思路:若令本人的鞋码与大于本人的鞋交换,则最后一个人的鞋子会变小,即,该方案不成立

若令相同鞋码的人交换,则成立;所以我们的思路是:令相同鞋码的人两两交换,最后判断是否每个人都成功交换,

令 a[i] 表示交换过的鞋码,若没有人交换则a[i] == i ,如此来判断是否有人没交换, 用 mp[x] 表示当前的 x 码的鞋子的最后一个人的编号,若 x 鞋码再次出现,则令 mp[x] 保存的鞋码的编号与本次的编号交换,并更新 mp[x] 

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;

const int N = 2e5+10;

int T;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

void solve()
{
    int n;
    int a[N] = {0};
    string s;

    scanf("%d", &n);
    map<int, int> mp;
    int x;
    int f = 0;
    for(int i = 1; i <= n; i ++ )
    {
        a[i] = i;
        scanf("%d", &x);
        if(mp[x] == 0) mp[x] = a[i];
        else
        {
            swap(a[mp[x]], a[i]);
            mp[x] = a[mp[x]];
        }
    }

    for(int i = 1; i <= n; i ++ )
    {
        if(a[i] == i)
        {
            puts("-1");
            return;
        }
    }

    for(int i = 1; i <= n; i ++ )
    {
        cout << a[i] << " ";
    }
    puts("");

    return;
}

int main()
{
    scanf("%d", &T);

    while(T -- )
        solve();

    return 0;
}

C. Sum of Substrings

C. Sum of Substrings 

思路:可判断知道,字符串的开头的 1 对结果贡献 10 ,字符串的结尾的 1 对结果贡献 1 ,其余部分的 1 对结果贡献为 11,如此我们仅需判断是否有足够的 移动次数,先使字符串最后一个 1 移动到字符串结尾的位置,然后再使第一个 1 移动到字符串开头的位置,如此可最大程度的减小 1 对结果的贡献

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;

const int N = 2e5+10;

int T;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

void solve()
{
    int n, m;
    LL res = 0;
    string s;
    scanf("%d %d", &n, &m);
    cin >> s;
    int a[N], cnt = 0;
    for(int i = 0; i < s.size(); i ++ )
    {
        if(s[i] == '1') a[cnt++] = i, res += 11;
    }

    // 特例只有 0
    if(cnt == 0)
    {
        cout << 0 << endl;
        return ;
    }
    
    // 特例只有一个 1 ,只判断移动到末尾或移动到开头,防止这个 1 既移动到末尾,又移动到开头
    if( m >= n - a[cnt-1] - 1)
    {
        res -= 10, m -= n - a[cnt-1] - 1;
        if(cnt == 1)
        {
            cout << res << endl;
            return;
        }
    }
    
    if( m >= a[0] ) res --, m -= a[0];

    cout << res << endl;

    return;
}

int main()
{
    scanf("%d", &T);

    while(T -- )
        solve();

    return 0;
}

D. Max GEQ Sum

D. Max GEQ Sum

思路:单调栈 + st表(st表存前缀和)

根据每个 a[i] ,用单调栈找到以 a[i] 为最大值的最大区间( L[ i ] + 1, R[ i ] - 1 ) ,判断目标区间中的最大区间和是否大于 a[i] 即可,若大于,则不成立,反之成立

最大区间和求法:以 i 为分界线,后半段的最大值 - 前半段的最小值,利用前缀和求目标区间的最大值,(后半段至少比前半段多 w[i] ,当元素组的 i 的后半段全小于零时)

注意:初始化 st表 时 从 0 开始初始化,因为不仅求max 还有 min ,求 max 时,预处理数组0处的0不妨碍求 max,求 min 时,可能前半段的最小值为 0 即,前半段的数组元素都不选择,此时,若不预处理0,结果无法取到0)

求前半段时 querymin( l1 - 1, i - 1) ,此处的 l1 - 1 是取 0 的情况( L[i] 一定是第一个大于 a[i] 的数,但也可能是 索引为 0 的 0 元素),若 L[i] 是0元素,则最小值为 0 ,这也是为什么初始化 st表时要从0开始的原因

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;

const int N = 2e5+5, M = 20;

int T;
int n, w[N];
LL s[N];
LL fmx[N][M], fmi[N][M];

void init()
{
    for(int j = 0; j < M; j ++ )
        for(int i = 0; i + (1 << j) - 1 <= n; i ++ )
            if(!j) fmx[i][j] = fmi[i][j] = s[i];
            else
            {
                fmx[i][j] = max(fmx[i][j-1], fmx[i + (1 << j - 1)][j-1]);
                fmi[i][j] = min(fmi[i][j-1], fmi[i + (1 << j - 1)][j-1]);
            }
}

LL querymx(int l, int r)
{
    int k = log2(r - l + 1);
    return max(fmx[l][k], fmx[r - (1 << k) + 1][k]);
}

LL querymi(int l, int r)
{
    int k = log2(r - l + 1);
    return min(fmi[l][k], fmi[r - (1 << k) + 1][k]);
}

void solve()
{
    scanf("%d", &n);

    for(int i = 1; i <= n; i ++ )
    {
        scanf("%d", &w[i]);
        s[i] = s[i-1] + w[i];
    }

    init();

    int l[N], r[N];
    stack<int> stk;
    for(int i = 1; i <= n; i ++ )
    {
        while(stk.size() && w[stk.top()] <= w[i]) stk.pop();
        if(stk.size()) l[i] = stk.top();
        else l[i] = -1;
        stk.push(i);
    }

    while(stk.size()) stk.pop();

    for(int i = n; i >= 1; i -- )
    {
        while(stk.size() && w[stk.top()] <= w[i]) stk.pop();
        if(stk.size()) r[i] = stk.top();
        else r[i] = -1;
        stk.push(i);
    }

    for(int i = 1; i <= n; i ++ )
    {
        int l1 = (l[i] == -1 ? 1: l[i] + 1);
        int r1 = (r[i] == -1 ? n: r[i] - 1);

        if(l1 == r1) continue;
        //printf("i : %d w[i] : %4d  l1 : %4d r1 : %4d\n", i, w[i], l1, r1 );
        if( querymx(i, r1) - querymi(l1 - 1, i - 1) - w[i] > 0 )
        {
            //printf("i : %d  %lld %lld %d\n", i, querymx(i, r1), querymi(l1-1, i-1), w[i]);
            //printf("i : %d  %lld %lld %d\n", i, querymx(i, r1), querymi(l1, i-1), w[i]);
            puts("NO");
            return;
        }
    }

    puts("YES");

    return;
}

int main()
{

    scanf("%d", &T);

    while(T -- )
        solve();

    return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AC自动寄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值