Codeforces Round #681 (Div. 2)

传送门

Codeforces Round #681 (Div. 2, based on VK Cup 2019-2020 - Final)

A

[ 1 , 4 n ] [1,4n] [1,4n] 选择 n n n 个数字,使任意数对 ( x , y ) (x,y) (x,y) 都不满足 g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1;以及 x ∣ y x|y xy y ∣ x y|x yx。对于第一个限制,可以赋所有数字一个大于 1 1 1 的公约数,显然赋 2 2 2 可以在规定区间内获得更多满足要求的数字。对于第二个条件,使所有数字除了公约数,另一个因子不满足可相互整除,那么选择 [ n + 1 , 2 n ] [n+1,2n] [n+1,2n] 即可满足条件。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = n + 1; i <= (n << 1); ++i)
        {
            printf("%d%c", i << 1, i == (n << 1) ? '\n' : ' ');
        }
    }
    return 0;
}
B

若只有一个连续 ′ 1 ′ '1' 1 的区域,答案为 a a a;若有多个这样的区域,从左往右贪心地考虑第二个及之后的区域,若直接引爆,花费为 a a a,若选择和左一个区域一起引爆,设两个区域间有 n n n ′ 0 ′ '0' 0,花费为 n × b n\times b n×b。若 n × b > a n\times b > a n×b>a 则单独引爆;反之,选择连接左一个区域后一起引爆。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005
char mp[maxn];

int main()
{
    int t, a, b;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &a, &b);
        scanf(" %s", mp);
        bool f = 0;
        int n = strlen(mp), cnt = 0, res = 0;
        for (int i = 0; i < n; ++i)
        {
            f |= mp[i] == '1';
            if (mp[i] == '0')
            {
                if (f)
                    ++cnt;
            }
            else if (cnt > 0)
            {
                res += cnt * b < a ? cnt * b : a;
                cnt = 0;
            }
        }
        printf("%d\n", res + (f ? a : 0));
    }
    return 0;
}
C

设两个集合 S , T S,T S,T 分别代表选择快递员配送与自己去取两种选择的餐厅,那么答案为 m a x { a i } + s u m { b j } , a i ∈ S , b j ∈ T max\{a_i\}+sum\{b_j\},a_i\in S,b_j\in T max{ai}+sum{bj},aiS,bjT。对于确定的 m a x { a i } max\{a_i\} max{ai} 显然最优的做法是将满足 a i ′ ≤ m a x { a i } a_{i'}\leq max\{a_i\} aimax{ai} 的餐厅全部加入 S S S,使 s u m { b j } sum\{b_j\} sum{bj} 尽可能小。那么将餐厅按照 a i a_i ai 排序,枚举 m a x { a i } max\{a_i\} max{ai},用前缀和维护 s u m { b j } sum\{b_j\} sum{bj},就可以 O ( n l o g n + n ) O(nlogn+n) O(nlogn+n) 求解最小花费时间。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 200005
typedef long long ll;
typedef pair<ll, ll> P;
ll sum[maxn];
P ps[maxn];

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%lld", &ps[i].first);
        for (int i = 0; i < n; ++i)
            scanf("%lld", &ps[i].second);
        sort(ps, ps + n);
        for (int i = 0; i < n; ++i)
            sum[i + 1] = sum[i] + ps[i].second;
        ll res = sum[n];
        for (int i = 0; i < n; ++i)
        {
            ll t = max(ps[i].first, sum[n] - sum[i + 1]);
            res = min(res, t);
        }
        printf("%lld\n", res);
    }
    return 0;
}
D 补题

数组应该由两个数组相加构成:一个非严格递增数组,即 [ k , n ) [k,n) [k,n) 的减一操作,和一个非严格递减数组,即 [ 0 , k ) [0,k) [0,k) 的减一操作。从左向右扫描,为了满足非严格递增数组,那么非严格递减数组应该尽可能的大。设 l e f t , r i g h t left,right left,right 分别代表某个位置左侧非严格递减数组能提供的最大值,与非严格递增数组可能提供的最小值。那么有
{ r i g h t = m a x ( A i − l e f t , 0 ) , l e f t = m i n ( l e f t , A [ i ] ) r i g h t ≤ A [ i ] − l e f t l e f t = A [ i ] − r i g h t A [ i ] ≥ r i g h t > A [ i ] − l e f t i m p o s s i l b l e o t h e r w i s e \begin{cases} right = max(A_i-left,0),left = min(left,A[i]) & right\leq A[i]-left\\ left=A[i]-right & A[i]\geq right > A[i]-left \\ impossilble & otherwise \\ \end{cases} right=max(Aileft,0),left=min(left,A[i])left=A[i]rightimpossilblerightA[i]leftA[i]right>A[i]leftotherwise

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 30005
int A[maxn];

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", A + i);
        bool f = 1;
        int left = A[0], right = -1e9;
        for (int i = 1; i < n; ++i)
        {
            if (right > A[i] - left)
            {
                if (right > A[i])
                {
                    f = 0;
                    break;
                }
                else
                    left = A[i] - right;
            }
            else
            {
                right = max(A[i] - left, 0);
                left = min(left, A[i]);
            }
        }
        puts(f ? "YES" : "NO");
    }
    return 0;
}
E 补题
F 补题
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值