Codeforces Round #780 (Div. 3)

Codeforces Round #780 (Div. 3)

请添加图片描述

A. Vasya and Coins

题意:

小明有 a a a枚1元硬币和 b b b枚2元硬币,输出小明无法支付的最小金额。

思路:

  1. 没有1元硬币:

答案为1

  1. 有1元硬币:

答案为 a + 2 ∗ b + 1 a+2*b+1 a+2b+1

时间复杂度:

O ( 1 ) O(1) O(1)

AC代码:
在这里插入图片描述

在这里插入代码片#include<bits/stdc++.h>

typedef long long ll;

const int N = 20,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

void solve()
{
    int a,b;
    std::cin>>a>>b;
    if(!a)
    {
        std::cout<<1<<'\n';
        return;
    }
    std::cout<<a+b*2+1<<'\n';
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

B. Vlad and Candies

题意:

有n种糖果,每个糖果有 a i a_{i} ai份。

每次都吃掉份数最多的糖果,但是小明不希望连续两次吃一样的糖果,他是否可以按照这个要求吃掉所有糖果。

思路:

只需要考虑最大值和次大值即可。

最 大 值 − 次 大 值 > 1 : N O 最大值 - 次大值 > 1:NO >1:NO
最 大 值 − 次 大 值 ≤ 1 : Y E S 最大值 - 次大值 \leq 1:YES 1:YES

时间复杂度:

O ( n ) O(n) O(n)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 20,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

void solve()
{
    int max1 = 0,max2 = 0;
    int n;
    std::cin>>n;
    for(int i = 1 ; i <= n ; i++)
    {
        int x;
        std::cin>>x;
        if(x > max1)std::swap(max1,x);
        if(x > max2)std::swap(max2,x);
    }
    std::cout<<(max1-max2 > 1 ?"NO":"YES")<<'\n';
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

C. Get an Even String

题意:

给定一个字符串S,要求你删除最少的字母,让字符串S满足如下要求:

  1. 长度为偶数
  2. a i = a i + 1 ( i 为 奇 数 ) a_{i}=a_{i+1}(i为奇数) ai=ai+1(i)

思路:

很显然,我们要把相同的字母匹配起来。
我们考虑如下贪心策略:

形如测试案例:bmefbmuyw

  1. 删除字母最少,就是保留字母最多
  2. 我们把上述字符串中,最近的匹配字母取出,组成区间
  3. [ 1 , 5 ] , [ 2 , 6 ] [1,5],[2,6] [1,5],[2,6]
  4. 即在这些区间中,找到尽可能多的不相交区间。
  5. 而选择的标准就是右端点越小,那么选择一定是越好的,因为右端点越小,后面可供选择的区间一定会更多。

所以实际操作过程中,每当存在一对可以匹配的字母,我们就匹配他们,并把他们中间的字母全部删除(让右端点尽可能小)。

时间复杂度:

使用了map去存字母,所以时间复杂度增加 l o g n logn logn
O ( n l o g n ) O(nlogn) O(nlogn)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 20,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

void solve()
{
    std::map<char,bool> mp;
    std::string s;
    std::cin>>s;
    int res = 0;
    for(int i = 0 ; i < s.size() ; i++)
    {
        if(mp.count(s[i]))
        {
            res += 2;
            mp.clear();
        }
        else mp[s[i]] = true;
    }
    std::cout<<s.size() - res << '\n';
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

D. Maximum Product Strikes Back

题意:

给定长度为n的数组,而且其中的每一个元素 ∣ a i ∣ ≤ 2 |a_{i}|\leq 2 ai2
要求从右和从左删除一定个数的元素,使得剩下元素相乘之积最大:

选择 x x x y y y
m a x ∏ i = x n − y a i max\prod_{i=x}^{n-y}a_{i} maxi=xnyai

思路:

因为空数组是1,所以0是必然被删除的,所以0把整个数组划分成了若干个区间,我们对每个这样的区间求取最大值,对每个区间,我们做这样的处理:

  1. 区间的值应该保持为正数
  2. 我们记录区间中负数的个数和2的个数
  3. 2的个数决定乘积大小,负数个数决定乘积是否为负。
  4. 在乘积已经是正数的基础上,那么区间的数留下的越多肯定是越好的。
  5. 区间内负数个数为偶数:

直接把当前区间乘积最为备选答案,与此时的答案相比。

  1. 区间内负数个数为奇数:

分别从左和从右寻找第一个负数,取两者更优的情况。

时间复杂度:

O ( n ) O(n) O(n)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 2e5+10,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

int a[N];

void solve()
{
    int n;
    int cnt_two = 0,cnt_negative = 0,ans = 0,last = 0;
    std::pair<int,int> res;
    std::cin>>n;
    for(int i = 1 ; i <= n ; i++)std::cin>>a[i];
    for(int i = 1 ; i <= n + 1; i++)
    {
        if(a[i] == 0||i == n + 1)
        {
            int t = 0;
            if(cnt_negative&1)
            {
                for(int j = last + 1 ; j < i ; j++)
                {
                    if(a[j] == 2||a[j] == -2)t++;
                    if(a[j] < 0)
                    {
                        if(cnt_two - t > ans)
                        {
                            ans = cnt_two - t;
                            res = {j, n + 1 - i};
                        }
                        break;
                    }
                }
                t = 0;
                for(int j = i - 1; j > last ; j--)
                {
                    if(a[j] == 2||a[j] == -2)t++;
                    if(a[j] < 0)
                    {
                        if(cnt_two - t > ans)
                        {
                            ans = cnt_two - t;
                            res = {last,n + 1 - j};
                        }
                        break;
                    }
                }
            }
            else
            {
                if(cnt_two > ans)
                {
                    ans = cnt_two;
                    res = {last,n + 1 - i};
                }
            }
            last = i;
            cnt_negative = cnt_two = 0;
        }
        else
        {
            if(a[i] == 2)cnt_two++;
            else if(a[i]==-2)cnt_two++,cnt_negative++;
            else if(a[i]==-1)cnt_negative++;
        }
    }
    if(ans == 0)std::cout<<n<<" "<<0<<'\n';
    else std::cout<<res.first<<" "<<res.second<<'\n';
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

E. Matrix and Shifts

题意:

有一个 n ∗ n n*n nn的矩阵,里面的每个元素都是0和1,可以任意执行以下4种操作(无需任何代价):

  1. 全体上移一行(第一行到最后一行)
  2. 全体下移一行(最后行到第一行)
  3. 全体左移一行(最左边一行到最右边一行)
  4. 全体右移一行(最右边一行到最左边一行)

操作完后,我们可以花费一个代价,执行这样的操作:

把某个元素从0变成1,或者从1变成0。

要求变完以后,只有对角线元素是1,其余均是0。
输出最小代价。

思路:

我们只要让尽可能多的1落在对角线上就可以了。
即以如下方式遍历矩阵:

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

记录下 1 最多的数量 m a x max max
那么最后要修改的数量就是:

  1. 在对角线上的 0 元素( n − m a x n-max nmax)
  2. 不在对角线上的 1 元素( c n t − m a x cnt-max cntmax)

记录矩阵中 1 的个数为 c n t cnt cnt
所以最终答案为 ( n − m a x ) + ( c n t − m a x ) (n-max)+(cnt-max) (nmax)+(cntmax)

时间复杂度:

O ( n 2 ) O(n^{2}) O(n2)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 2e3+10,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

int a[N][N];

void solve()
{
    int n,cnt = 0,max = 0;
    std::cin>>n;
    for(int i = 1 ; i <= n ; i++)
    {
        std::string s;
        std::cin>>s;
        for(int j = 1 ; j <= n ; j++)
        {
            a[i][j] = s[j-1] - '0';
            cnt += (a[i][j] == 1);
        }
    }
    for(int j = 1 ; j <= n ; j++)
    {
        int y = j,temp = 0;
        for(int i = 1 ; i <= n ; i++)
        {
            if(a[i][y] == 1)temp++;
            y++;
            if(y==n+1)y = 1;
        }
        max = std::max(max,temp);
    }
    std::cout<<cnt - max + (n - max)<<'\n';
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T;
    std::cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

F1. Promising String (easy version)

题意:

给定一个由’+'和‘-’组成的字符串S,定义有希望的字符串如下:

字符串可以进行如下操作:

相邻的两个’-‘可以合并为’+’

可以通过上述操作,使得字符串中’+'和‘-’的数量相同。

输出字符串S中所有满足条件的子串的个数。

思路:

因为数据量只有3000,所以我们直接暴力枚举所有区间。
检查区间合法的方法如下:

  1. 记录下区间中‘+‘的数量cnt1,‘-‘的数量cnt0,以及可以合并的减号的最大对数cnt。
  2. 假设合并的减号对数为 x x x:

c n t 0 − 2 ∗ x = c n t 1 + x cnt_{0}-2*x=cnt_{1}+x cnt02x=cnt1+x
c n t 0 − c n t 1 = 3 ∗ x cnt_{0}-cnt_{1}=3*x cnt0cnt1=3x

那么只需要满足 x x x为整数,而且 x ≤ c n t x \leq cnt xcnt,区间就是合法的。

时间复杂度:

O ( n 2 ) O(n^{2}) O(n2)

AC代码:

在这里插入图片描述

#include<bits/stdc++.h>

typedef long long ll;

const int N = 2e3+10,M = 2e4+10,INF = 0x3f3f3f3f,mod = 1e9+7;

void solve()
{
    int n;
    std::cin>>n;
    std::string s;
    std::cin>>s;
    bool tag = false;
    int cnt1,cnt0,cnt,res = 0;
    for(int i = 0 ; i < n ; i++)
    {
        cnt = 0,cnt1 = 0,cnt0 = 0;
        for(int j = i ; j < n ; j++)
        {
            if(s[j] == '+')cnt1++,tag = false;
            else
            {
                if(tag)
                {
                    cnt++;
                    cnt0++;
                    tag = false;
                }
                else
                {
                    cnt0++;
                    tag = true;
                }
            }
            if(cnt0==cnt1)res++;
            else
            {
                if(cnt0 > cnt1 && (cnt0 - cnt1) % 3 == 0)
                {
                    if(cnt >= (cnt0 - cnt1)/3 )res++;
                }
            }
        }
    }
    std::cout<<res<<'\n';
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值