Codeforces Round #397 (Div. 1 + Div. 2 combined) 题解(CF765A,CF765B,CF765C,CF765D,CF765E,CF765F)

A.Neverending competitions(Codeforces 765A)

题解:直接判断坐飞机的次数是奇数还是偶数就可以了。

#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

char h[100];
int n;

int main() {
    scanf("%d", &n);
    scanf("%s", h + 1);
    for (int i = 1; i <= n; i ++) 
        scanf("%s", h + 1);
    if (n % 2 == 0) printf("home\n"); else
        printf("contest\n");
}

B.Code obfuscation(Codeforces 765B)

题解:根据题意,记录做到第当前位置最大的字母是什么,判断当前位置是否和法,然后更新最大的字母。

#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 505;

char s[MAXN];

int main() {
    scanf("%s", s + 1);
    int len = strlen(s + 1), now = -1;
    for (int i = 1; i <= len; i ++) {
        if (s[i] - 'a' > now + 1) {
            printf("NO\n");
            return 0;
        }  
        now = max(s[i] - 'a', now);
    }
    printf("YES\n");
}

C.Table Tennis Game 2(Codeforces 765C)

题解:首先判断是否进行了至少一盘的游戏。然后a/n+b/n就是进行盘数最多的答案。但是有一种特殊的不合法的情况就是,a/n==0且b%n!=0时,肯定是不合法的,因为a没有赢过,一直是b赢,但是b%n!=0又证明b输过,矛盾。b/n==0且a%n!=0同理。

#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

int main() {
    int n, a, b;
    scanf("%d%d%d", &n, &a, &b);
    int ans = a / n + b / n;
    if (a / n == 0 && b % n != 0 || b / n == 0 && a % n != 0) ans = 0;
    if (ans == 0) printf("-1\n"); else printf("%d\n", ans);
}

D. Artsem and Saunders(Codeforces 765D)

题解:设有上下两排点,各有m个和n个,对于下面的点i,我们在上面设一个点j,强行令h[j]=f[i],那么令g[i]=h[j]即可,不合法情况就是f[f[i]]!=f[i]。

#include <bits/stdc++.h>
#define fe first
#define se second

using namespace std;

const int maxn = 100005;

int f[maxn],g[maxn],h[maxn],vis[maxn],n,m;

int main()
{
    scanf("%d", &n);
    for(int i = 1;i <= n;i ++) scanf("%d", &f[i]);
    for(int i = 1;i <= n;i ++)
        if (f[f[i]] != f[i]) {printf("-1\n");return 0;}
    for(int i = 1;i <= n;i ++)
    {
        if (!vis[f[i]]) vis[f[i]] = ++ m,h[m] = f[i];
        g[i] = vis[f[i]];
    }
    printf("%d\n", m);
    for(int i = 1;i <= n;i ++) printf("%d%c", g[i],i == n ? '\n' : ' ');
    for(int i = 1;i <= m;i ++) printf("%d%c", h[i],i == m ? '\n' : ' ');
    return 0;
}

E. Tree Folding(Codeforces 765E)

题解:首先假如有解,最后剩下的一条链肯定是直径,然后再把直径不断的对折。也就是说,无论怎么操作,只要能成功答案就一定是一样的。我们可以先随便设一个节点为根。从底向上合并上来。对于一个非根节点,儿子的深度一定要相同才能合并。对于根节点则可以存在两种什么。当合并时存在非根的不合法点是,直接把这个点设为根再跑一遍找答案,如果都不可以答案就是-1。否则令找到的链长度不断除二直到除不尽。

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

const int MAXN = 2e5 + 5;

int n, root;
int tot, Last[MAXN], Next[MAXN * 2], Go[MAXN * 2];

void link(int u, int v) {
    Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;
}

int dfs(int now, int pre) {
    set<int> q;
    for (int p = Last[now]; p; p = Next[p]) {
        int v = Go[p];
        if (v == pre) continue;
        int tmp = dfs(v, now);
        if (tmp == -1) return -1;
        q.insert(tmp + 1);
    }
    if (q.size() == 0) return 0;
    if (q.size() == 1) return *q.begin();
    if (q.size() == 2 && !pre) return *q.begin() + *q.rbegin();
    root = now;
    return -1;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        link(u, v), link(v, u);
    }
    int ans = dfs(1, 0);
    if (ans == -1 && root) ans = dfs(root, 0);
    for (; (ans & 1) == 0; ans /= 2);
    printf("%d\n", ans);
}

F. Souvenirs(Codeforces 765F)

题解:把询问离线,考虑把数一个个加入序列中更新答案。假设从右往左加数,当前加到了第l个数,令b[i]=min{|a[j]-a[i]|j>i,i>l},用线段树维护b数组。显然b数组从左到右是单调不下降的。那么对于每个询问就是要求各前缀最小值,根据这个我们发现我们不需要把全部的b求出来。有些不必要的更新,即假设对于j

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

const int MAXN = 1e5 + 5, MAXM = 3e5 + 5;
const int Inf = 1e9;

struct Query {
    int l, r, id;
} que[MAXM];

struct Node {
    int mn;
    set<int> d;
} tr[MAXN * 4];

int n, m, a[MAXN], ans[MAXM];

bool cmp(Query a, Query b) {
    return a.l > b.l;
}

void build(int now, int l, int r) {
    tr[now].mn = Inf;
    for (int i = l; i <= r; i ++) tr[now].d.insert(a[i]);
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(now * 2, l, mid), build(now * 2 + 1, mid + 1, r);
}

int query(int now, int l, int r, int lx, int rx) {
    if (rx < l || lx > r) return Inf;
    if (l >= lx && r <= rx) return tr[now].mn;
    int mid = (l + r) >> 1;
    return min(query(now * 2, l, mid, lx, rx), query(now * 2 + 1, mid + 1, r, lx, rx));
}

void modify(int now, int l, int r, int lx, int rx, int num, int &mn) {
    if (rx < l || lx > r) return;
    if (l == r) {
        tr[now].mn = min(tr[now].mn, abs(a[l] - num));
        mn = min(mn, tr[now].mn);
        return;
    }
    set<int> :: iterator p = tr[now].d.lower_bound(num);
    if ((p == tr[now].d.end() || (*p - num >= mn)) && (p == tr[now].d.begin() || (num - *(-- p) >= mn))) {
        mn = min(mn, query(now, l, r, lx, rx));
        return;
    }
    int mid = (l + r) >> 1;
    modify(now * 2, l, mid, lx, rx, num, mn), modify(now * 2 + 1, mid + 1, r, lx, rx, num, mn);
    tr[now].mn = min(tr[now * 2].mn, tr[now * 2 + 1].mn);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; i ++) {
        scanf("%d%d", &que[i].l, &que[i].r);
        que[i].id = i;
    }
    sort(que + 1, que + m + 1, cmp);
    build(1, 1, n);
    for (int i = 1, lst = n, tmp; i <= m; i ++) {
        for (;lst >= que[i].l; lst --) 
            modify(1, 1, n, lst + 1, n, a[lst], tmp = Inf);
        ans[que[i].id] = query(1, 1, n, que[i].l, que[i].r);
    }
    for (int i = 1; i <= m; i ++) printf("%d\n", ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值