2014-2015 ACM-ICPC, Asia Tokyo Regional Contest

 

2014-2015 ACM-ICPC, Asia Tokyo Regional Contest

 

 

A B C D E F G H I J K
O O O O   O O        

 

A - Bit String Reordering

签到

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

const int N = 20;
int b[N], p[N], n, m, cnt[2];
int temp[N];

int put(int opt) {
    int cnt2[2] = {0};
    int index = 0;
    for (int i = 1; i <= m; i++) {
        int num = p[i];
        while (num--) {
            temp[++index] = opt;
        }
        opt ^= 1;
    }
    for (int i = 1; i <= n; i++) cnt2[temp[i]]++;
    if (cnt2[0] != cnt[0] || cnt2[1] != cnt[1]) return 1e9;
    int j = 1;
    int res = 0;
    for (int i = 1; i <= n; i++) {
        if (b[i] == 1) {
            while (temp[j] != 1) j++;
            res += abs(i - j);
            j++;
        }
    }
    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &b[i]), cnt[b[i]]++;
    for (int i = 1; i <= m; i++)
        scanf("%d", &p[i]);
    printf("%d\n", min(put(0), put(1)));
    return 0;
}
View Code

 

B - Miscalculation

签到

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

char s[30];
int res, st[30];
int top;

int main() {
    scanf("%s%d", s + 1, &res);
    int len = strlen(s + 1);
    int ans1 = s[1] - '0';
    for (int i = 3; i <= len; i += 2) {
        if (s[i - 1] == '+') {
            ans1 += s[i] - '0';
        } else {
            ans1 *= s[i] - '0';
        }
    }
    st[++top] = s[1] - '0';
    for (int i = 3; i <= len; i += 2) {
        if (s[i - 1] == '*') {
            st[top] *= s[i] - '0';
        } else {
            st[++top] = s[i] - '0';
        }
    }
    int ans2 = 0;
    for (int i = 1; i <= top; i++) ans2 += st[i];
    if (ans1 == res && ans2 == res) puts("U");
    else if (ans1 == res) puts("L");
    else if (ans2 == res) puts("M");
    else puts("I");
    return 0;
}
View Code

 

C - Shopping

如果两个区间存在包含关系,那么肯定直接走到最大的 $d$ 再走到最小的 $c$ 最优。

如果两个区间交叉,那么之间应该是三段距离,分别设为 $a$, $b$, $c$

如果先走左区间再走右区间,那么走的路程为 $a + b + a + b + a + b + c + b + c + b + c= 3a + 5b + 3c$

如果先走右区间再走坐去间,那么走的路程为 $a + b + c + a + b + c + a + b + c = 3a + 3b + 3c$

 所以就是把所有交叉的区间合并成一个大区间,然后每次到区间右端点再走回一遍左端点。

用并查集实现即可。

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

const int N = 1007;
int fa[N], mx[N], mn[N];

int getfa(int x) {
    return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}

void unit(int x, int y) {
    x = getfa(x), y = getfa(y);
    if (x == y) return;
    fa[x] = y;
    mx[y] = max(mx[y], mx[x]);
    mn[y] = min(mn[y], mn[x]);
}

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) fa[i] = mx[i] = mn[i] = i;
    while (m--) {
        int l, r;
        scanf("%d%d", &l, &r);
        for (int i = l; i < r; i++)
            unit(i, i + 1);
    }
    int ans = n + 1;
    for (int i = 1; i <= n; i++)
        if (getfa(i) == i) 
            ans += (mx[i] - mn[i]) * 2;
    printf("%d\n", ans);
}
View Code

 

D - Space Golf

高中物理杀我!!!我高考考的最烂的就是物理了!!!

能不能跨过一个板只跟 $v_y$ 有关。枚举一下要弹多少次,然后二分一下 $v_y$,可以求出 $v_x$,得到的 $v_y$ 不一定使合速度最小,因为合速度是一个对勾函数,三分或者判断一下就行。

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

const int N = 20;
const double eps = 1e-5;
int d, n, b;
int p[N], h[N];
double loc[N];

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}

bool check(int cnt, double vy) {
    double per_time = vy * 2.0;
    double total_time = per_time * cnt;
    double vx = d / total_time;
    for (int i = 1; i <= cnt; i++) {
        double l = loc[i - 1], r = loc[i];
        for (int j = 1; j <= n; j++) {
            if (dcmp(p[j] - l) < 0 || dcmp(p[j] - r) > 0) continue;
            double cur_time = p[j] / vx;
            int times = cur_time / per_time;
            cur_time -= times * per_time;
            if (dcmp(vy * cur_time - 0.5 * cur_time * cur_time - h[j]) < 0) return 0;
        }
    }
    return 1;
}

double check0(int cnt, double vy) {
    double per_time = vy * 2.0;
    double total_time = per_time * cnt;
    double vx = d / total_time;
    return sqrt(vx * vx + vy * vy);
}

int main() {
    freopen("in.txt", "r", stdin);
    scanf("%d%d%d", &d, &n, &b);
    for (int i = 1; i <= n; i++) 
        scanf("%d%d", p + i, h + i);
    double ans = 2e4;
    for (int i = 1; i <= b + 1; i++) {
        bool flag = 0;
        if (d % i == 0) {
            int per = d / i;
            for (int j = 1; j <= n; j++)
                if (p[j] % per == 0) {
                    flag = 1;
                    break;
                }
        }
        if (flag) continue;
        double per = 1.0 * d / i;
        for (int j = 1; j <= i; j++) 
            loc[j] = per * j;
        double l = 0, r = 2e4;
        for (int cnt = 0; cnt < 100; cnt++) {
            double mid = (l + r) / 2.0;
            if (check(i, mid)) r = mid;
            else l = mid;
        }
        r = 2e4;
        for (int cnt = 0; cnt < 100; cnt++) {
            double ll = l + (r - l) / 3.0, rr = r - (r - l) / 3.0;
            if (check0(i, ll) < check0(i, rr)) r = rr;
            else l = ll;
        }
        ans = min(ans, check0(i, l));
    }
    printf("%.5f\n", ans);
    return 0;
}
View Code

 

F - There is No Alternative

这 $n$ 也出得太小了!!!本质就是求哪些边一定存在于所有最小生成树上。那么就是CF原题了。

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

const int N = 1e5 + 7;
int n, m;
struct Edge {
    int u, v, cost, id;
    bool operator < (const Edge &rhs) const {
        return cost < rhs.cost;
    }
} edge[N], edge2[N];

struct E { 
    int v, ne, id;
} e[N];
int head[N], cnt, ans[N];

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

int fa[N], dfn[N], low[N], tol;
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }

void dfs(int u, int id) {
    low[u] = dfn[u] = ++tol;
    for (int i = head[u]; ~i; i = e[i].ne) {
        int v = e[i].v;
        if (!dfn[v]) {
            dfs(v, i);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) ans[e[i].id] = 0;
        } else if (i != (id ^ 1)) {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

inline void unite(int u, int v) {
    u = getfa(u);
    v = getfa(v);
    if (u != v) fa[u] = v;
}

int main() {
    //freopen("in.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 0; i < m; i++) {
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
        edge[i].id = i;
    }
    memcpy(edge2, edge, sizeof(edge2));
    sort(edge, edge + m);
    for (int i = 0; i < m; ) {
        int j = i;
        while (j + 1 < m && edge[j + 1].cost == edge[j].cost) j++;
        cnt = tol = 0;
        for (int k = i; k <= j; k++) {
            edge[k].u = getfa(edge[k].u);
            edge[k].v = getfa(edge[k].v);
            int u = edge[k].u, v = edge[k].v;
            head[u] = head[v] = -1;
            dfn[u] = dfn[v] = low[u] = low[v] = 0;
        }
        for (int k = i; k <= j; k++) {
            int u = edge[k].u, v = edge[k].v, id = edge[k].id;
            if (u == v) {
                //printf("%d\n", k);
                ans[id] = 2;
                continue;
            }
            ans[id] = 1;
            add(u, v, id);
        }
        for (int k = i; k <= j; k++) 
            if (!dfn[edge[k].u]) dfs(edge[k].u, -1);
        for (; i <= j; ++i)
            unite(edge[i].u, edge[i].v);
    }
    int ans1 = 0;
    long long ans2 = 0;
    for (int i = 0; i < m; i++) 
        if (ans[i] == 0) ans1++, ans2 += edge2[i].cost;
    printf("%d %lld\n", ans1, ans2);
    return 0;
}
View Code

 

G - Flipping Parentheses

这道题能写出来是因为大一上学期刚学C语言接触了括号序列判定是否合法的题。当时还没学栈,所以想了一个做法。把左括号看成 +$1$,右括号看成 -$1$,每个点表示当前的前缀和。

那么序列合法等价于,前缀和数组没有位置小于0,且最后一个数等于0。

对于这个题,在位置 $x$ 修改一个括号,就相当于区间 $[x, n]$ 加(减)2。

如果把一个左括号变成右括号,相当于区间 $-2$,那么只需要找当最左边的 $-1$位置,使它加 $2$ 就能使序列合法。

如果把一个右括号变成左括号,相当于区间 $+2$,那么找到第一个前缀和大于 $1$ 的位置,从他之后第一个 $1$ 变成 $-1$ 即可,这里我选择二分找那个位置。应该有1log的做法。

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

const int N = 3e5 + 7;
int x[N], sum[N], n;
char s[N];

struct Seg {
    #define lp p << 1
    #define rp p << 1 | 1
    int tree[N << 2][2];
    void pushup(int p) {
        tree[p][0] = min(tree[lp][0], tree[rp][0]);
        tree[p][1] = min(tree[lp][1], tree[rp][1]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            if (l == 1 || l == n) {
                tree[p][0] = tree[p][1] = N;
                return;
            }
            if (x[l] == 1) tree[p][0] = l, tree[p][1] = N;
            else tree[p][0] = N, tree[p][1] = l;
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
    void update(int p, int l, int r, int pos) {
        if (l == r) {
            swap(tree[p][0], tree[p][1]);
            return;
        }
        int mid = l + r >> 1;
        if (pos <= mid) update(lp, l, mid, pos);
        else update(rp, mid + 1, r, pos);
        pushup(p);
    }
    int query(int p, int l, int r, int x, int y, int opt) {
        if (x <= l && y >= r) return tree[p][opt];
        int mid = l + r >> 1;
        int ans = N;
        if (x <= mid) ans = min(ans, query(lp, l, mid, x, y, opt));
        if (y > mid) ans = min(ans, query(rp, mid + 1, r, x, y, opt));
        return ans;
    }
} seg;

struct Seg1 {
    #define lp p << 1
    #define rp p << 1 | 1
    int tree[N << 2], lazy[N << 2];
    void pushup(int p) {
        tree[p] = min(tree[lp], tree[rp]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tree[p] = sum[l];
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
    void tag(int p, int val) {
        tree[p] += val;
        lazy[p] += val;
    }
    void pushdown(int p) {
        if (lazy[p]) {
            tag(lp, lazy[p]);
            tag(rp, lazy[p]);
            lazy[p] = 0;
        }
    }
    void update(int p, int l, int r, int x, int y, int val) {
        if (x <= l && y >= r) {
            tree[p] += val;
            lazy[p] += val;
            return;
        }
        int mid = l + r >> 1;
        pushdown(p);
        if (x <= mid) update(lp, l, mid, x, y, val);
        if (y > mid) update(rp, mid + 1, r, x, y, val);
        pushup(p);
    }
    int query(int p, int l, int r, int x, int y) {
        if (x <= l && y >= r) return tree[p];
        int mid = l + r >> 1;
        pushdown(p);
        int ans = N;
        if (x <= mid) ans = min(ans, query(lp, l, mid, x, y));
        if (y > mid) ans = min(ans, query(rp, mid + 1, r, x, y));
        return ans;
    }
    void print(int p, int l, int r){
        if (l == r){
            printf("%d ", tree[p]);
            return;
        }
        int mid = l + r >> 1;
        pushdown(p);
        print(lp, l, mid);
        print(rp, mid + 1, r);
    }
} seg1;

int get(char ch) {
    if (ch == '(') return 1;
    return -1;
}

int main() {
    freopen("in.txt", "r", stdin);
    int q;
    scanf("%d%d", &n, &q);
    scanf("%s", s + 1);
    for (int i = 1; i <= n; i++)
        x[i] = get(s[i]), sum[i] = sum[i - 1] + x[i];
    seg.build(1, 1, n);
    seg1.build(1, 1, n);
    for (int u; q--; ) {
        scanf("%d", &u);
        if (u == 1 || u == n) {
            printf("%d\n", u);
            continue;
        }
        seg.update(1, 1, n, u);
        if (x[u] == 1) seg1.update(1, 1, n, u, n, -2);
        else seg1.update(1, 1, n, u, n, 2);
        x[u] *= -1;
        int opt = (x[u] == 1 ? 0 : 1);
        if (opt == 1) {
            int pos = seg.tree[1][opt];
            printf("%d\n", pos);
            x[pos] *= -1;
            seg.update(1, 1, n, pos);
            seg1.update(1, 1, n, pos, n, 2);
        } else {
            int l = 1, r = n;
            int temp = 0;
            while (l <= r) {
                int mid = l + r >> 1;
                if (seg1.query(1, 1, n, mid, n) >= 2) r = mid - 1, temp = mid;
                else l = mid + 1;
            }
            int pos = seg.query(1, 1, n, temp, n, opt);
            printf("%d\n", pos);
            x[pos] *= -1;
            seg.update(1, 1, n, pos);
            seg1.update(1, 1, n, pos, n, -2);
        }
    }
    return 0;
}
View Code

 还真有1log的

相当于查区间最后一个小于2的位置,那么先查右子树,如果右子树最小值小于2,就返回右,否则返回左。

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

const int N = 3e5 + 7;
int x[N], sum[N], n;
char s[N];

struct Seg {
    #define lp p << 1
    #define rp p << 1 | 1
    int tree[N << 2][2];
    void pushup(int p) {
        tree[p][0] = min(tree[lp][0], tree[rp][0]);
        tree[p][1] = min(tree[lp][1], tree[rp][1]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            if (l == 1 || l == n) {
                tree[p][0] = tree[p][1] = N;
                return;
            }
            if (x[l] == 1) tree[p][0] = l, tree[p][1] = N;
            else tree[p][0] = N, tree[p][1] = l;
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
    void update(int p, int l, int r, int pos) {
        if (l == r) {
            swap(tree[p][0], tree[p][1]);
            return;
        }
        int mid = l + r >> 1;
        if (pos <= mid) update(lp, l, mid, pos);
        else update(rp, mid + 1, r, pos);
        pushup(p);
    }
    int query(int p, int l, int r, int x, int y, int opt) {
        if (x <= l && y >= r) return tree[p][opt];
        int mid = l + r >> 1;
        int ans = N;
        if (x <= mid) ans = min(ans, query(lp, l, mid, x, y, opt));
        if (y > mid) ans = min(ans, query(rp, mid + 1, r, x, y, opt));
        return ans;
    }
} seg;

struct Seg1 {
    #define lp p << 1
    #define rp p << 1 | 1
    int tree[N << 2], lazy[N << 2];
    void pushup(int p) {
        tree[p] = min(tree[lp], tree[rp]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tree[p] = sum[l];
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
    void tag(int p, int val) {
        tree[p] += val;
        lazy[p] += val;
    }
    void pushdown(int p) {
        if (lazy[p]) {
            tag(lp, lazy[p]);
            tag(rp, lazy[p]);
            lazy[p] = 0;
        }
    }
    void update(int p, int l, int r, int x, int y, int val) {
        if (x <= l && y >= r) {
            tree[p] += val;
            lazy[p] += val;
            return;
        }
        int mid = l + r >> 1;
        pushdown(p);
        if (x <= mid) update(lp, l, mid, x, y, val);
        if (y > mid) update(rp, mid + 1, r, x, y, val);
        pushup(p);
    }
    int query(int p, int l, int r) {
        if (tree[p] > 1) return l;
        if (l == r) return l;
        int mid = l + r >> 1;
        pushdown(p);
        if (tree[rp] <= 1) return query(rp, mid + 1, r);
        return query(lp, l, mid);
    }
    void print(int p, int l, int r){
        if (l == r){
            printf("%d ", tree[p]);
            return;
        }
        int mid = l + r >> 1;
        pushdown(p);
        print(lp, l, mid);
        print(rp, mid + 1, r);
    }
} seg1;

int get(char ch) {
    if (ch == '(') return 1;
    return -1;
}

int main() {
    freopen("in.txt", "r", stdin);
    int q;
    scanf("%d%d", &n, &q);
    scanf("%s", s + 1);
    for (int i = 1; i <= n; i++)
        x[i] = get(s[i]), sum[i] = sum[i - 1] + x[i];
    seg.build(1, 1, n);
    seg1.build(1, 1, n);
    for (int u; q--; ) {
        scanf("%d", &u);
        if (u == 1 || u == n) {
            printf("%d\n", u);
            continue;
        }
        seg.update(1, 1, n, u);
        if (x[u] == 1) seg1.update(1, 1, n, u, n, -2);
        else seg1.update(1, 1, n, u, n, 2);
        x[u] *= -1;
        int opt = (x[u] == 1 ? 0 : 1);
        if (opt == 1) {
            int pos = seg.tree[1][opt];
            printf("%d\n", pos);
            x[pos] *= -1;
            seg.update(1, 1, n, pos);
            seg1.update(1, 1, n, pos, n, 2);
        } else {
            int l = 1, r = n;
            int temp = seg1.query(1, 1, n) + 1;
            int pos = seg.query(1, 1, n, temp, n, opt);
            printf("%d\n", pos);
            x[pos] *= -1;
            seg.update(1, 1, n, pos);
            seg1.update(1, 1, n, pos, n, -2);
        }
    }
    return 0;
}
View Code

 

posted @ 2019-09-29 22:23  Mrzdtz220  阅读(372)  评论(0)    收藏  举报