Codeforces Round #600 (Div. 2)

Posted kisekipurin2019

tags:

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

A - Single Push

题意:给数组a和数组b,可以选择一段连续的区间[l,r]使得ai全部加k(k>0)至多一次。求能不能从a变成b。

题解:一开始作差排序去重,然后判断差是不是只有1个(且>=0)或只有两个(且c1=0,c2>0),但这样是错的,比如下面的样例。

1
5
1 1 1 1 1
2 1 2 2 2

因为虽然差都是1但不是连续的区间。

做法是作差,然后判断是否有至多一个正的方波。可以用两个变量,一个记录是否进入了方波,且方波的高是多少。另一个记录是否离开了方波。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int mod = 1e9 + 7;
 
ll pow_mod(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}
 
int n, a[100005], b[100005];
 
void test_case() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &b[i]);
        b[i] -= a[i];
    }
    int in = 0, out = 0;
    for(int i = 1; i <= n; ++i) {
        if(b[i] < 0) {
            puts("NO");
            return;
        } else if(b[i] > 0) {
            if(in == 0)
                in = b[i];
            else if(out || in != b[i]) {
                puts("NO");
                return;
            }
        } else if(in == 1)
            out = 1;
    }
    puts("YES");
    return;
}
 
int main() {
#ifdef KisekiPurin
    freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
    int t = 1;
    scanf("%d", &t);
    for(int ti = 1; ti <= t; ++ti) {
        //printf("Case #%d: ", ti);
        test_case();
    }
}

但第二天早上发现方波其实是什么?数列后面加上一个0,那么一个方波的差分就一定至多各有一个+a和-a。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;

ll pow_mod(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}

int n, a[100005], b[100005];

void test_case() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &b[i]);
        b[i] -= a[i];
    }
    b[n + 1] = 0;
    for(int i = n + 1; i >= 1; --i)
        b[i] -= b[i - 1];

    int tmp = 0;
    for(int i = 1; i <= n + 1; ++i) {
        if(b[i] > 0) {
            if(tmp == 0)
                tmp = b[i];
            else {
                puts("NO");
                return;
            }
        } else if(b[i] < 0) {
            if(tmp == -b[i])
                tmp = -1;
            else {
                puts("NO");
                return;
            }
        }
    }
    if(tmp == 0 || tmp == -1)
        puts("YES");
    else
        puts("NO");
    return;
}

int main() {
#ifdef KisekiPurin
    freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
    int t = 1;
    scanf("%d", &t);
    for(int ti = 1; ti <= t; ++ti) {
        //printf("Case #%d: ", ti);
        test_case();
    }
}

假如把n+1的项去掉,也可以“检测不到bi<0”则认为成功。

还有一种写法是,作差之后把两边的0缩掉,然后判断中间的区间都全等。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;

ll pow_mod(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}

int n, a[100005], b[100005];

void test_case() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &b[i]);
        b[i] -= a[i];
    }
    int L = 1, R = n;
    while(L <= R && b[L] == 0)
        ++L;
    while(L <= R && b[R] == 0)
        --R;
    bool suc = 1;
    if(L <= R) {
        if(b[L] < 0)
            suc = 0;
        else {
            for(int i = L; i <= R; ++i) {
                if(b[i] != b[L]) {
                    suc = 0;
                    break;
                }
            }
        }
    }
    if(suc)
        puts("YES");
    else
        puts("NO");
    return;
}

int main() {
#ifdef KisekiPurin
    freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
    int t = 1;
    scanf("%d", &t);
    for(int ti = 1; ti <= t; ++ti) {
        //printf("Case #%d: ", ti);
        test_case();
    }
}

B - Silly Mistake

题意:有个打卡机,序号a的人打卡上班+a,打卡下班-a。但是分隔天数的记录没了。规定每天每人只能上班至多一次,且上班后必须下班。求一种划分天数的方法,无解输出-1。贪心构造一种划分天数最多的方法,每次所有人下班之后就开一天新的,这样不容易导致同一个人上班多次(当然假如遇到这个上班过的人再开一天新的就是划分天数最少的方法)。记得最后一天要判断所有人都下班了!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mod = 1e9 + 7;

ll pow_mod(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}


int n, a[100005], cnt[1000005], vis[1000005];
int ans[50005], atop;

void test_case() {
    //memset(cnt, 0, sizeof(cnt));
    //memset(vis, 0, sizeof(vis));

    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);

    atop = 0;
    int pre = 0, cntm = 0;
    for(int i = 1; i <= n; ++i) {
        if(a[i] > 0) {
            ++cnt[a[i]];
            ++vis[a[i]];
            if(cnt[a[i]] == 1)
                ++cntm;
            else {
                puts("-1");
                return;
            }
        } else {
            --cnt[-a[i]];
            if(cnt[-a[i]] == 0) {
                --cntm;
                if(cntm == 0) {
                    for(int k = pre + 1; k <= i; ++k) {
                        if(a[k] < 0)
                            continue;
                        if(vis[a[k]] > 1) {
                            puts("-1");
                            return;
                        }
                        vis[a[k]] = 0;
                    }
                    ans[++atop] = i;
                    pre = i;
                }
            } else {
                puts("-1");
                return;
            }
        }
    }
    if(cntm != 0) {
        puts("-1");
        return;
    }

    for(int i = atop; i >= 1; --i)
        ans[i] -= ans[i - 1];
    printf("%d
", atop);
    for(int i = 1; i <= atop; ++i)
        printf("%d%c", ans[i], " 
"[i == atop]);
    return;
}

int main() {
#ifdef KisekiPurin
    freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
    int t = 1;
    //scanf("%d", &t);
    for(int ti = 1; ti <= t; ++ti) {
        //printf("Case #%d: ", ti);
        test_case();
    }
}

当然去重还是用nlogn的方法最方便,比如来个set,insert之前看一下,这样写起来(或许)快,没有上面的这么复杂。

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

第五天打卡 Codeforces Round #600 (Div. 2)

cf比赛记录Codeforces Round #600 (Div. 2)

Codeforces Round #600 (Div. 2)

Codeforces Round #600 (Div. 2) E. Antenna Coverage

Codeforces Round #600 (Div. 2) A. Single Push

Codeforces Round #600 (Div. 2) B. Silly Mistake