Codeforces Round #446 (Div. 2)

Posted zjp_shadow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #446 (Div. 2)相关的知识,希望对你有一定的参考价值。

Codeforces Round #446 (Div. 2)

  • 总体:rating涨了好多,虽然有部分是靠和一些大佬(例如redbag和ShichengXiao)交流的……希望下次能自己做出来2333

A. Greed

  • 题意:给你\(n\)个罐子,每个罐子都告诉了你它当前的饮料体积和它的总容积,问能否用两个罐子装下所有饮料(\(n\le 100000\)

  • 题解:简单模拟即可,用两个最大的算一下,注意累和会爆\(long long\)

int a[100100], b[100100];
long long sum = 0;
int main () {
    int n = read();
    For (i, 1, n) {
        a[i] = read();
        sum += a[i];
    }
    For (i, 1, n)
        b[i] = read();
    sort (b + 1, b + 1 + n);
    if (b[n] + b[n - 1] >= sum)
        puts("YES");
    else
        puts("NO");
    return 0;
}

B. Wrath

  • 题意:给你一个长度为\(n\)序列,每个点有个\(l\)值,会覆盖他前面\(l\)个点,问最后还剩多少个点没有被覆盖。(\(n\le 100000\)

  • 题解:应该用差分简单做一下就行了,脑子一抽写了个线段树上去,幸亏过了2333(就当练手吧)

const int N = 1e6 + 1e3;
int sum[N << 2];

#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r 
void Build(int o, int l, int r) {
    if (l == r) { sum[o] = 1; return ; }
    int mid = (l + r) >> 1;
    Build(lson); Build(rson);
    sum[o] = sum[o << 1] + sum[o << 1 | 1];
}

int ul, ur;
int lazy[N << 2];
void push_down(int o) {
    if (!lazy[o]) return;
    lazy[o << 1] = lazy[o << 1 | 1] = 1; 
    sum[o << 1] = sum[o << 1 | 1] = 0; lazy[o] = 0; 
}

void Update(int o, int l, int r) {
    if (ul <= l && r <= ur) { lazy[o] = 1; sum[o] = 0; return ;}
    push_down(o); int mid = (l + r) >> 1;
    if (ul <= mid) Update(lson); if (ur > mid) Update(rson);
    sum[o] = sum[o << 1] + sum[o << 1 | 1];
}

int main () {
    int n = read();
    Build(1, 1, n);
    For (i, 1, n) {
        int len = read();
        if (i == 1) continue ;
        if (!len) continue ;
        ul = max(i - len, 1); ur = i - 1;
        Update(1, 1, n);
    }
    printf ("%d\n", sum[1]);
    return 0;
}

C. Pride

  • 题意:给你一个长为\(n\)序列,你能进行一个操作,将相邻两个数中的一个替换为他们的\(gcd\),问至少进行多少次操作能把他们全部变成\(1\),如果不能完成输出\(-1\)。(\(n\le 2000\)
  • 题解:这题一开始搞了我好久QAQ,想错了。其实就是先弄出一个\(1\),然后可以把其他所有的数字都变成\(1\),剩下的步数就是\(n-1\)。找那个步数,一定是一段连续区间\(gcd=1\)的情况,然后你用\(O(n^2)\)去枚举一下,找到一个可行的最小长度。还需要特判一开始就有\(1\)的情况,不然会挂掉(我就惨遭hack了TAT,后来又hack了两个可怜鬼233)。
const int N = 2010;
int a[N], n, ans = 0x7f7f7f7f, res, now;

int main () {
    n = read();
    res = n;
    For (i, 1, n) {
        a[i] = read();
        if (a[i] == 1) -- res;  
        now = __gcd(now, a[i]);
    }
    if (now != 1)
        return puts("-1"), 0;
    if (res != n)
        return printf ("%d\n", res), 0;
    For (i, 1, n) {
        int here = a[i], len = 0;
        if (here == 1) {
            ans = 0;
            continue ;
        }
        Fordown (j, i - 1, 1) {
            ++ len;
            here = __gcd(here, a[j]);
            if (here == 1) {
                chkmin(ans, len);
                break;
            }
        }
    }
    printf ("%d\n", ans + n - 1);
    return 0;
}

D. Gluttony

  • 题意:给你一个长为\(n\)序列,其中每个数字都不相同,让你输出一个原序列的一个排列,使得他们中任意一个子集(不能为空集或者全集)的和都互不相同(就是相同位置上的数的和互不相同就行了)(\(n\le 22\)
  • 题解:一开始不知道做法,redbag大佬讲出来了正解,就是将每一个数换成后一个比它大的数,最大的数换成最小的那一个,就行了。

  • 证明:这个还是比较好证明的。

考虑分两种情况讨论:
1.原子集没有最大的那个数:这就显然是个正确的,每个数都比之前的数要大,所以总和肯定要大;

2.原子集有最大的那个数:最大数改变后的值最整个里面最大的,然后你将这个子集去掉最大的那个数,剩下的变化量的和肯定要小于你最大值变为最小值的值,因为你之间肯定会有多余的空格(因为不能为全集)留着,所以肯定是可行的啦。

int n, a[25];
struct node {
    int val, pos;
    bool operator < (const node &rhs) const {
        return val < rhs.val;
    }
};
node lt[25];
int ans[25];

int main () {
    n = read();
    For (i, 1, n) {
        lt[i].val = read();
        lt[i].pos = i;
    }
    sort (lt + 1, lt + 1 + n);
    For (i, 1, n) 
        if (i != n)
            ans[lt[i].pos] = lt[i + 1].val;
        else 
            ans[lt[i].pos] = lt[1].val;
    For (i, 1, n)
        printf ("%d ", ans[i]);
    return 0;
}

E. Envy

一个最小生成树的题目,待填坑2333

以上是关于Codeforces Round #446 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #446 (Div. 2) AGreed

Codeforces Round #446 (Div. 2) BWrath

Codeforces Round #446 Div. 1

Codeforces Round #446 (Div. 2) CPride

Codeforces Round #446 Div1 E

Codeforces Round #446 (Div. 1) C - Envy