Codeforces Beta Round #19

 

A. World Football Cup

#include <bits/stdc++.h>
using namespace std;
 
const int N = 60;
char name[N][N];
map<string, int> mp;
char s[N];
 
struct P {
    int id, point;
    int dif, goal;
    bool operator < (const P &rhs) const {
        if (point == rhs.point && goal - dif == rhs.goal - rhs.dif) return goal > rhs.goal;
        if (point == rhs.point) return goal - dif > rhs.goal - rhs.dif;
        return point > rhs.point;
    }
} p[N];
 
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s", name[i]);
        mp[name[i]] = i;
        p[i].id = i;
    }
    for (int i = 0; i < n * (n - 1) / 2; i++) {
        int pp, qq;
        scanf("%s%d:%d", s, &pp, &qq);
        int j = 0;
        int len = strlen(s);
        char s1[50] = {};
        char s2[50] = {};
        int p1 = 0, p2 = 0;
        for (; s[j] != '-'; j++) s1[p1++] = s[j];
        j++;
        for (; j < len; j++) s2[p2++] = s[j];
        int a = mp[s1], b = mp[s2];
        p[a].goal += pp, p[b].goal += qq;
        p[a].dif += qq; p[b].dif += pp;
        if (pp > qq) p[a].point += 3;
        else if (pp == qq) p[a].point++, p[b].point++;
        else p[b].point += 3;
    }
    sort(p, p + n);
    vector<string> ans;
    for (int i = 0; i < n / 2; i++)
        ans.push_back(name[p[i].id]);
    sort(ans.begin(), ans.end());
    for (auto x: ans)
        cout << x << '\n';
    return 0;
}
View Code

 

B. Checkout Assistant

有$n$个商品,每个商品价格$c_i$,售货员处理这件商品需要时间$t_i$,偷走一个商品需要$1$个单位时间,问怎么安排这些商品的结账顺序可以使的最后要还的钱最少。

如果让一件商品去结账,相当于花$c_i$块钱,能偷走买走至多$t_i + 1$个商品,要使最后总花费最小,那么就是01背包了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
 
const int N = 2020;
ll dp[N];
int w[N];
ll c[N];
 
int main() {
    memset(dp, 0x3f, sizeof dp);
    dp[0] = 0;
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%lld", &w[i], &c[i]), w[i]++;
    for (int i = 1; i <= n; i++) {
        for (int j = n; j >= 1; j--) {
            dp[j] = min(dp[j], dp[max(j - w[i], 0)] + c[i]);
        }
    }
    printf("%lld\n", dp[n]);
    return 0;
}
View Code

 

C. Deletion of Repeats

有一个序列,每种元素至多出现$10$次,如果有一个子串前一半等于后一半,那么把前一半及以前的字符全部删掉,要求从短的以及较左的地方开始删,问最后这个串长什么样。

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

const int N = 1e5 + 7;
int a[N], v[N];
vector<int> G[N];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        v[i] = a[i];
    }
    sort(v + 1, v + 1 + n);
    int cnt = unique(v + 1, v + 1 + n) - v - 1;
    for (int i = 1; i <= n; i++) {
        a[i] = lower_bound(v + 1, v + 1 + cnt, a[i]) - v;
        G[a[i]].push_back(i);
    }
    int now = 0;
    for (int i = 2; i <= n; i++) {
        bool flag = 0;
        for (auto pos: G[a[i]]) {
            flag = 1;
            if (pos >= i) continue;
            if (n - i + 1 < i - pos) continue;
            if (pos <= now) continue;
            flag = 0;
            for (int j = 1; j < i - pos; j++) {
                if (a[i + j] != a[pos + j]) {
                    flag = 1;
                    break;
                }
            }
            if (!flag) break;
        }
        if (!flag) now = i - 1;
    }
    printf("%d\n", n - now);
    for (int i = now + 1; i <= n; i++)
        printf("%d%c", v[a[i]], " \n"[i == n]);
    return 0;
}
View Code

 

D. Points

一个二维坐标系,有三个操作。

1.加点

2.删点

3.查询严格在$(x, y)$右上角的点,输出$x$坐标最小的那个点,如果有相同的,则输出$y$最小的,不存在输出$-1$

因为存在修改操作,那么就不能离线做了,用线段树维护$x$坐标下$y$坐标的最大值,然后就变成了查询$\left[x + 1, inf\right]$中最小的$x$其$y$大于要查询的$y$,那么就又是先查左及剪枝的那个写法了。然后找到对应$x$坐标后,加点删点用一个set维护每个$x$坐标出现过$y$的坐标,在这个set里面lower_bound一下就好了,刚开始都插入0以及所有$y$坐标都加个一会好操作很多。

#include <bits/stdc++.h>
using namespace std;
 
const int N = 5e5 + 7;
 
struct Seg {
    #define lp p << 1
    #define rp p << 1 | 1
    int mx[N << 2];
    void pushup(int p) {
        mx[p] = max(mx[lp], mx[rp]);
    }
    void update(int p, int l, int r, int x, int val) {
        if (l == r) {
            mx[p] = max(val, mx[p]);
            return;
        }
        int mid = l + r >> 1;
        if (x <= mid) update(lp, l, mid, x, val);
        else update(rp, mid + 1, r, x, val);
        pushup(p);
    }
    void change(int p, int l, int r, int x, int val) {
        if (l == r) {
            mx[p] = val;
            return;
        }
        int mid = l + r >> 1;
        if (x <= mid) change(lp, l, mid, x, val);
        else change(rp, mid + 1, r, x, val);
        pushup(p);
    }
    int query(int p, int l, int r, int x, int y, int val) {
        if (x > y) return -1;
        if (mx[p] <= val) return -1;
        if (l == r) return l;
        int mid = l + r >> 1;
        if (x <= mid) {
            int temp = query(lp, l, mid, x, y, val);
            if (temp != -1) return temp;
        }
        return query(rp, mid + 1, r, x, y, val);
    }
} seg;
 
struct OPT {
    int opt;
    int x, y;
} o[N];
int v[N];
set<int> st[N];
 
int main() {
//    freopen("in.txt", "r", stdin);
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        char s[10] = {};
        scanf("%s%d%d", s, &o[i].x, &o[i].y);
        if (s[0] == 'a') o[i].opt = 0;
        else if (s[0] == 'r') o[i].opt = 1;
        else o[i].opt = 2;
        v[i] = o[i].x;
        o[i].y++;
    }
    sort(v + 1, v + 1 + n);
    int cnt = unique(v + 1, v + 1 + n) - v - 1;
    for (int i = 1; i <= cnt; i++) st[i].insert(0);
    for (int i = 1; i <= n; i++) 
        o[i].x = lower_bound(v + 1, v + 1 + cnt, o[i].x) - v;
    for (int i = 1; i <= n; i++) {
        if (o[i].opt == 0) {
            st[o[i].x].insert(o[i].y);
            seg.update(1, 1, cnt, o[i].x, o[i].y);
        } else if (o[i].opt == 1) {
            st[o[i].x].erase(o[i].y);
            set<int>::iterator it = st[o[i].x].end();
            it--;
            int res = 0;
            res = *it;
            seg.change(1, 1, cnt, o[i].x, res);
        } else {
            int pos = seg.query(1, 1, cnt, o[i].x + 1, cnt, o[i].y);
            if (pos == -1) printf("-1\n");
            else {
                int ans = *st[pos].upper_bound(o[i].y);
                printf("%d %d\n", v[pos], ans - 1);
            }
        }
    }
    return 0;
}
View Code

 

E. Fairy

一个图为二分图的充要条件就是不存在奇环。
先求出一个dfs树,然后考虑非树边对dfs树的影响。
有几种情况需要考虑。
一、不存在自环及奇环
都可以删。
二、自环
如果存在两个自环及以上,就不可能了,因为它只能删除一条边。
有一个自环,当不存在奇环的时候就只能删除这个自环,否则也没边可删了。
三、存在一个奇环
那么这个奇环上的树边及非树边都可以删。也只有这种情况能删非树边。
四、存在多个奇环
那么能删除的边就是这些奇环的树边的交集。同时,这个交集的边不能出现在偶环上,否则奇环+偶环还是会得到奇环。
那么树上差分一下得到每条边在多少个奇环上,如果在偶环上就把路径减一下,就能处理出不能在偶环上的情况。最后就判断一下每一条边的值是否为奇环的个数。

#include <bits/stdc++.h>

namespace IO {
    void read() {}
    template<class T, class... T2>
    void read(T &x, T2 &... oth) {
        x = 0; T f = 1; char ch = getchar();
        while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
        x *= f;
        read(oth...);
    }
}

const int N = 1e6 + 7;
struct E {
    int v, ne, id;
} e[N << 1];
int head[N], tag[N], dep[N], cnt = 1;
bool vis[N];
int self, n, m;

void add(int u, int v, int id) {
    e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].id = id; head[u] = cnt;
    e[++cnt].v = u; e[cnt].ne = head[v]; e[cnt].id = id; head[v] = cnt;
}

int tol, fei;

void dfs(int u, int f) {
    for (int i = head[u]; i; i = e[i].ne) {
        if (i == (f ^ 1)) continue;
        int v = e[i].v;
        if (dep[v]) {
            if (dep[v] > dep[u]) continue;
            if ((dep[u] - dep[v] + 1) & 1) {
                tol++;
                fei = e[i].id;
                tag[u]++; tag[v]--;
            } else {
                tag[u]--; tag[v]++;
            }
        } else {
            dep[v] = dep[u] + 1;
            dfs(v, i);
            tag[u] += tag[v];
        }
    }
}

std::vector<int> vec;

void dfs(int u) {
    vis[u] = 1;
    for (int i = head[u]; i; i = e[i].ne) {
        int v = e[i].v;
        if (vis[v]) continue;
        if (tag[v] == tol)
            vec.push_back(e[i].id);
        dfs(v);
    }
}

int main() {
    IO::read(n, m);
    for (int i = 1; i <= m; i++) {
        int u, v;
        IO::read(u, v);
        if (u == v && !self) {
            self = i;
            continue;
        }
        if (u == v) {
            self = -1;
            continue;
        }
        add(u, v, i);
    }
    if (self == -1) {
        puts("0");
        return 0;
    }
    for (int i = 1; i <= n; i++) {
        if (!dep[i])
            dep[i] = 1, dfs(i, 0);
    }
    if (tol == 0) {
        if (self) {
            printf("1\n%d\n", self);
        } else {
            printf("%d\n", m);
            for (int i = 1; i <= m; i++)
                printf("%d%c", i, " \n"[i == m]);
        }
        return 0;
    }
    if (self) {
        puts("0");
        return 0;
    }
    for (int i = 1; i <= n; i++)
        if (!vis[i])
            dfs(i);
    if (tol == 1)
        vec.push_back(fei);
    printf("%d\n", (int)vec.size());
    std::sort(vec.begin(), vec.end());
    for (int i = 0; i < vec.size(); i++)
        printf("%d%c", vec[i], " \n"[i + 1 == vec.size()]);
    return 0;
}
View Code

 

posted @ 2019-10-14 18:48  Mrzdtz220  阅读(146)  评论(0编辑  收藏  举报