Skip to content

2018 Multi-University Training Contest 5

Contents

A. Always Online

Unsolved.

B.Beautiful Now

Solved.

题意:

给出一个 nk

每次可以将 n 这个数字上的某两位交换,最多交换 k 次,求交换后的最大和最小值。

思路:

很明显有一种思路,对于最小值,尽可能把小的放前面,对于最大值,尽可能把打的放前面。

但是如果有多个最小数字或者最大数字会无法得出放哪个好,因此 BFS 一下即可。

Code
#include <bits/stdc++.h>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;

struct node {
    int num, idx, step;
    node() {}
    node(int num, int idx, int step) : num(num), idx(idx), step(step) {}
};

int n, k;
int cnt;
int arr[maxn];

int BFS1() {
    queue<node> q;
    q.push(node(n, cnt, 0));
    int ans = INF;
    while (!q.empty()) {
        node now = q.front();
        q.pop();
        ans = min(ans, now.num);
        if (now.step == k)
            continue;
        if (now.idx == 1)
            continue;
        int tmp = now.num;
        cnt = 0;
        while (tmp) {
            arr[++cnt] = tmp % 10;
            tmp /= 10;
        }
        int Min = now.idx;
        for (int i = now.idx - 1; i >= 1; --i) {
            if (arr[i] == arr[now.idx])
                continue;
            if (arr[i] == 0 && now.idx == cnt)
                continue;
            if (arr[i] < arr[Min])
                Min = i;
        }
        if (Min == now.idx) {
            q.push(node(now.num, now.idx - 1, now.step));
        } else {
            for (int i = now.idx - 1; i >= 1; --i) {
                if (arr[i] == arr[Min]) {
                    swap(arr[i], arr[now.idx]);
                    tmp = 0;
                    for (int j = cnt; j >= 1; --j) {
                        tmp = tmp * 10 + arr[j];
                    }
                    q.push(node(tmp, now.idx - 1, now.step + 1));
                    swap(arr[i], arr[now.idx]);
                }
            }
        }
    }
    return ans;
}

int BFS2() {
    queue<node> q;
    q.push(node(n, cnt, 0));
    int ans = -INF;
    while (!q.empty()) {
        node now = q.front();
        q.pop();
        ans = max(ans, now.num);
        if (now.step == k)
            continue;
        if (now.idx == 1)
            continue;
        int tmp = now.num;
        cnt = 0;
        while (tmp) {
            arr[++cnt] = tmp % 10;
            tmp /= 10;
        }
        int Max = now.idx;
        for (int i = now.idx - 1; i >= 1; --i) {
            if (arr[i] == arr[now.idx])
                continue;
            if (arr[i] > arr[Max])
                Max = i;
        }
        if (Max == now.idx) {
            q.push(node(now.num, now.idx - 1, now.step));
        } else {
            for (int i = now.idx - 1; i >= 1; --i) {
                if (arr[i] == arr[Max]) {
                    swap(arr[i], arr[now.idx]);
                    tmp = 0;
                    for (int j = cnt; j >= 1; --j) {
                        tmp = tmp * 10 + arr[j];
                    }
                    q.push(node(tmp, now.idx - 1, now.step + 1));
                    swap(arr[i], arr[now.idx]);
                }
            }
        }
    }
    return ans;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d %d", &n, &k);
        int tmp = n;
        cnt = 0;
        while (tmp) {
            cnt++;
            tmp /= 10;
        }
        k = min(k, cnt - 1);
        int ans1 = BFS1();
        int ans2 = BFS2();
        printf("%d %d\n", ans1, ans2);
    }
    return 0;
}

C. Call It What You Want

Unsolved.

D. Daylight

Unsolved.

E. Everything Has Changed

Solved.

题意:

求多个圆的周长并

思路:

对于不想交和内含的直接 continue,相切的直接相加。

对于相交的可以减去大圆上的弧长,加上小圆的弧长。

Code
#include <bits/stdc++.h>

using namespace std;

const double PI = acos(-1.0);
const double eps = 1e-8;

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

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) {
        x = _x;
        y = _y;
    }

    double distance(Point p) {
        return hypot(x - p.x, y - p.y);
    }
} P;

int n;
double R, r;

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d %lf", &n, &R);
        double ans = 2 * R * PI;
        for (int i = 1; i <= n; ++i) {
            scanf("%lf %lf %lf", &P.x, &P.y, &r);
            double dis = P.distance(Point(0.0, 0.0));
            if (sgn(dis - (r + R)) >= 0)
                continue;
            else if (sgn(dis - (R - r)) < 0)
                continue;
            else if (sgn(dis - (R - r)) == 0) {
                ans += 2 * PI * r;
                continue;
            }
            double arc1 = (R * R + dis * dis - r * r) / (2.0 * R * dis);
            arc1 = 2 * acos(arc1);
            double arc2 = (r * r + dis * dis - R * R) / (2.0 * r * dis);
            arc2 = 2 * acos(arc2);
            ans -= R * arc1;
            ans += r * arc2;
        }
        printf("%.10f\n", ans);
    }
    return 0;
}

F. Fireflies

Unsolved.

G. Glad You Came

Upsolved.

题意:

m 个区间操作,每次给 [L, R] 区间内小于 v 的数变为 v

思路:

线段树,维护最大最小值 + 剪枝,因为数据随机才可以这样做。

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

#define N 5000010
#define M 100010
#define ui unsigned int
#define ll long long
int t, n, m;
ui x, y, z, w;
ui f[N << 2];
ui MOD = (ui)1 << 30;

ui rng61() {
    x = x ^ (x << 11);
    x = x ^ (x >> 4);
    x = x ^ (x << 5);
    x = x ^ (x >> 14);
    w = x ^ y ^ z;
    x = y;
    y = z;
    z = w;
    return z;
}

struct SEG {
    ui lazy[M << 2], Max[M << 2], Min[M << 2];
    void Init() {
        memset(lazy, 0, sizeof lazy);
        memset(Max, 0, sizeof Max);
        memset(Min, 0, sizeof Min);
    }
    void pushup(int id) {
        Max[id] = max(Max[id << 1], Max[id << 1 | 1]);
        Min[id] = min(Min[id << 1], Min[id << 1 | 1]);
    }
    void pushdown(int id) {
        if (!lazy[id])
            return;
        lazy[id << 1] = lazy[id];
        Max[id << 1] = lazy[id];
        Min[id << 1] = lazy[id];
        lazy[id << 1 | 1] = lazy[id];
        Max[id << 1 | 1] = lazy[id];
        Min[id << 1 | 1] = lazy[id];
        lazy[id] = 0;
    }
    void update(int id, int l, int r, int ql, int qr, ui val) {
        if (Min[id] >= val)
            return;
        if (l >= ql && r <= qr && Max[id] < val) {
            lazy[id] = Max[id] = val;
            return;
        }
        pushdown(id);
        int mid = (l + r) >> 1;
        if (ql <= mid)
            update(id << 1, l, mid, ql, qr, val);
        if (qr > mid)
            update(id << 1 | 1, mid + 1, r, ql, qr, val);
        pushup(id);
    }
    int query(int id, int l, int r, int pos) {
        if (l == r)
            return Max[id];
        pushdown(id);
        int mid = (l + r) >> 1;
        if (pos <= mid)
            return query(id << 1, l, mid, pos);
        else
            return query(id << 1 | 1, mid + 1, r, pos);
    }
} seg;

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%u%u%u", &n, &m, &x, &y, &z);
        for (int i = 1; i <= 3 * m; ++i) f[i] = rng61();
        seg.Init();
        for (int i = 1, l, r, v; i <= m; ++i) {
            l = f[3 * i - 2] % n + 1;
            r = f[3 * i - 1] % n + 1;
            v = f[3 * i] % MOD;
            if (l > r)
                swap(l, r);
            seg.update(1, 1, n, l, r, v);
        }
        ll res = 0;
        for (int i = 1; i <= n; ++i) res ^= (ll)seg.query(1, 1, n, i) * (ll)i;
        printf("%lld\n", res);
    }
    return 0;
}

H. Hills And Valleys

Upsolved,

题意:

给出一个长为 n 的数字串,每一位范围是 [0, 9],可以翻转其中一段,使得最长非下降子序列最长。

思路:

也就是说,可以存在这样一段:

0, 1, 2, \cdots, x, (x - 1), y, (y - 1), \cdots, x, y + 1, y + 2, \cdots

我们知道,如果不可以翻转,求最长上升子序列的话,我们可以将原串和模式串 0123456789 求最长公共子序列。

那么翻转的话,我们通过枚举翻转的区间 C(2, 10) 构造出上述的模式串,再求最长公共子序列。

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

#define N 100010
#define INF 0x3f3f3f3f
int t, n, m, a[N], b[20];
int dp[N][20], tl[N][20], tr[N][20], res, l, r, ql, qr;

void solve() {
    for (int i = 1; i <= m; ++i) dp[0][i] = 0, tl[0][i] = -1, tr[0][i] = -1;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            dp[i][j] = dp[i - 1][j];
            tl[i][j] = tl[i - 1][j];
            tr[i][j] = tr[i - 1][j];
            if (a[i] == b[j]) {
                ++dp[i][j];
                if (j == ql && tl[i][j] == -1)
                    tl[i][j] = i;
                if (j == qr)
                    tr[i][j] = i;
            }
            if (j > 1 && dp[i][j - 1] > dp[i][j]) {
                dp[i][j] = dp[i][j - 1];
                tl[i][j] = tl[i][j - 1];
                tr[i][j] = tr[i][j - 1];
            }
        }
    if (ql == 1 && qr == 1) {
        res = dp[n][m];
        l = 1;
        r = 1;
    } else if (dp[n][m] > res && tl[n][m] != -1 && tr[n][m] != -1) {
        res = dp[n][m];
        l = tl[n][m];
        r = tr[n][m];
    }
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        res = 1, l = 1, r = 1;
        for (int i = 1; i <= n; ++i) scanf("%1d", a + i);
        for (int i = 1; i <= 10; ++i) b[i] = i - 1;
        m = 10;
        ql = 1, qr = 1;
        solve();
        for (int i = 1; i < m; ++i)
            for (int j = i + 1; j <= 10; ++j) {
                m = 0;
                for (int pos = 1; pos <= i; ++pos) b[++m] = pos - 1;
                ql = m + 1;
                for (int pos = j; pos >= i; --pos) b[++m] = pos - 1;
                qr = m;
                for (int pos = j; pos <= 10; ++pos) b[++m] = pos - 1;
                solve();
                // for (int i = 1; i <= m; ++i) printf("%d%c", b[i], " \n"[i == m]);
            }
        printf("%d %d %d\n", res, l, r);
    }
    return 0;
}

I. Innocence

Unsolved.

J. Just So You Know

Unsolved.

K. Kaleidoscope

Unsolved.

L. Lost In The Echo

Unsolved.


Last update: March 28, 2022
Created: March 28, 2022
Back to top