AtCoder Beginner Contest 223 复盘

打得很烂,预计 1500 只拿到了 700,甚至比 VP 打得还要差。

A

一遍 AC。

int main() {
    int x = read();
    if (x % 100 == 0 && x > 0) puts("Yes");
    else puts("No");
    return 0;
}

B

一遍 AC。

const int MAXN = 2000 + 10;

std::string ss;
std::string strs[MAXN];

int main() {
    cin >> ss;
    strs[1] = ss;
    for (int i = 2; i <= ss.length(); ++i) {
        strs[i] = strs[i - 1];
        char last = strs[i][0];
        strs[i].erase(strs[i].begin());
        strs[i] += last;
    }
    std::sort(strs + 1, strs + 1 + ss.length());
    cout << strs[1] << endl;
    cout << strs[ss.length()] << endl;
    return 0;
}

C. Doukasen

垃圾解方程题,我被卡在第三个样例上了,没调出来,换了题解的写法才过。

其实这种解方程题并不用非得去找到特定位置然后列数据解方程,可以直接去把等式的值求出来,然后用这个值去求解,比如这个题的方程就是 \(\mathrm{ltime} + \frac{x}{B} = \mathrm{rtime} + \frac{A - x}{B}\),等式的意义是两边烧的时间相等(都是 \(\frac{1}{2}\sum\frac{A}{B}\),于是可以直接求这个东西,再带回原式求解。

const int MAXN = 1e5 + 10;

int n;
double aa[MAXN], bb[MAXN];
double burntime[MAXN];
double prefix[MAXN], suffix[MAXN];

int main() {
    n = read();
    for (int i = 1; i <= n; ++i){
        aa[i] = read(); bb[i] = read();
        burntime[i] = (double) aa[i] /(double) bb[i];
    }
    for (int i = 1; i <= n; ++i) {
        prefix[i] = prefix[i - 1] + burntime[i];
    }
    double len = 0;
    double tim = prefix[n] / 2.0;
    rep (i, 1, n) {
        if (prefix[i] > tim) {
            double dt = tim - prefix[i - 1];
            len += bb[i] * dt;
            printf("%.6lf\n", len);
            return 0;
        }
        len += aa[i];
    }
    return 0;
}

D. Restricted Permutation

第一眼看过去和《菜肴制作》差不多,其实还有些不一样,令最小的最靠前和令字典序最小这两个是不同的,前者需要建反图反着跑,后者建正图就可以了。核心思想都是利用优先队列代替普通队列。

const int MAXN = 2e5 + 10;

int n, m;

std::vector<int> G[MAXN];
int ind[MAXN];

int main() {
    n = read(); m = read();
    rep (i, 1, m) {
        int u = read(); int v = read();
        G[u].push_back(v);
        ++ind[v];
    }
    std::vector<int> ord;
    std::priority_queue<int, std::vector<int>, std::greater<int> > q;
    for (int i = 1; i <= n; ++i) {
        if (!ind[i]) {
            q.push(i);
        }
    }
    while (!q.empty()) {
        int u = q.top(); q.pop();
        ord.push_back(u);
        std::sort(ALL(G[u]));
        forall (G[u], i) {
            int v = G[u][i];
            --ind[v];
            if (!ind[v]) {
                q.push(v);
            }
        }
    }
    if (ord.size() != n) printf("-1");
    else for (auto v : ord) printf("%d ", v);
    puts("");
    return 0;
}

F. Parenthesis Checking

也是套路了,把左括号看成 \(+1\) 右括号看成 \(-1\),一个括号串合法等价于整个串的和为 \(0\) 且中间没有掉到负数(相对值),所以需要对原序列维护一个区间和,前缀和的最小值,后面这个东西有点反直觉但是也能直接维护。

考场上我懒得去费劲想这个东西了,所以我选择用线段树维护前缀和数组,一次操作等价于修改两个后缀 \([l, n]\) 和 \([r, n]\),查询就是查 \(r\) 和 \(l - 1\) 两个点的值和 \(l\) 到 \(r\) 的区间最小值。

然后区间最值写挂了,调一场没调出来。

#错误警示:想清楚区间修改到底是怎么修改的。基础题不要写错。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>

#define forall(G,i) for (int i = 0, __for_siz__ = (int) (G).size(); i < __for_siz__; ++i)
#define DEBUG(x) std::cerr << #x << " = " << x << endl;
#define rep(i_,a_,b_) for (int i_ = (a_); (i_) <= (b_); (i_) = (i_) + 1)
#define ALL(x) (x).begin(), (x).end()
#define MP std::make_pair
#define se second
#define endl '\n'
#define fi first

using std::cin;
using std::cout;

typedef long long int lli;

inline int read() {
    int s = 0, x = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
    while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); }
    return s * x;
}

inline lli readll() {
    lli s = 0, x = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); }
    while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); }
    return s * x;
}

const int MAXN = 4e5 + 10;

int n, q;
char ss[MAXN];

namespace Segt {
lli minx[MAXN << 2], sum[MAXN << 2];
lli tag[MAXN << 2];

#define ls (p << 1)
#define rs (p << 1 | 1)

void Update(int p) {
    sum[p] = sum[ls] + sum[rs];
    minx[p] = std::min(minx[ls], minx[rs]);
}
void buildTree(int p, int l, int r, lli *seq) {
    if (l == r) { minx[p] = sum[p] = seq[l]; return;  }
    int mid = (l + r) >> 1;
    buildTree(ls, l, mid, seq); buildTree(rs, mid + 1, r, seq);
    Update(p);
}
void Add(int p, lli l, lli r, lli k) {
    sum[p] += k * (r - l + 1);
    minx[p] += k;
    tag[p] += k;
}
void Pushdown(int p, int l, int r) {
    if (!tag[p]) return;
    int mid = (l + r) >> 1;
    Add(ls, l, mid, tag[p]); Add(rs, mid + 1, r, tag[p]);
    tag[p] = 0;
}
void Modify(int p, int l, int r, int ll, int rr, lli k) {
    if (l == ll && rr == r) { Add(p, l, r, k); return;  }
    int mid = (l + r) >> 1;
    Pushdown(p, l, r);
    if (rr <= mid) Modify(ls, l, mid, ll, rr, k);
    else if (mid + 1 <= ll) Modify(rs, mid + 1, r, ll, rr, k);
    else {
        Modify(ls, l, mid, ll, mid, k);
        Modify(rs, mid + 1, r, mid + 1, rr, k);
    }
    Update(p);
}
std::pair<lli, lli> Query(int p, int l, int r, int ll, int rr) {
    if (rr < 1) return {0, 0};
    if (l == ll && rr == r) return {sum[p], minx[p]};
    Pushdown(p, l, r);
    int mid = (l + r) >> 1;
    if (rr <= mid) return Query(ls, l, mid, ll, rr);
    else if (mid + 1 <= ll) return Query(rs, mid + 1, r, ll, rr);
    else {
        std::pair<lli, lli> lt = Query(ls, l, mid, ll, mid), rt = Query(rs, mid + 1, r, mid + 1, rr);
        return {lt.first + rt.first, std::min(lt.second, rt.second)};
    }
}
}

lli seq[MAXN];

int main() {
    scanf("%d %d", &n, &q);
    scanf("%s", ss + 1);
    rep (i, 1, n) {
        if (ss[i] == '(') seq[i] = 1;
        else seq[i] = -1;
        seq[i] += seq[i - 1];
    }
    Segt::buildTree(1, 1, n, seq);
    while (q --> 0) {
        int pos, l, r; scanf("%d %d %d", &pos, &l, &r);
        if (pos == 1) {
            lli tl = Segt::Query(1, 1, n, l, l).first - Segt::Query(1, 1, n, l - 1, l - 1).first;
            lli tr = Segt::Query(1, 1, n, r, r).first - Segt::Query(1, 1, n, r - 1, r - 1).first;
            Segt::Modify(1, 1, n, l, n, -tl + tr);
            Segt::Modify(1, 1, n, r, n, -tr + tl);
        } else {
            std::pair<lli, lli> fx = Segt::Query(1, 1, n, r, r), pref = Segt::Query(1, 1, n, l - 1, l - 1), px = Segt::Query(1, 1, n, l, r);
            if ((fx.first - pref.first) || (px.second - pref.first)) puts("No");
            else puts("Yes");
        }
    }
    return 0;
}
上一篇:手抖删掉mysql的生产库,一定要跑路么?


下一篇:【DB笔试面试223】在Oracle中,如果丢失一个数据文件而且没有备份,也没有归档日志,那么应该如何打开数据库?