AIM Tech Round 3 (Div. 2) ABCDE题解

来源:互联网 发布:淘宝怎么改会员名字 编辑:程序博客网 时间:2024/05/29 08:05

A. Juicer

水题。模拟放橙子的过程,大于尺寸直接跳过。刚开始没太读懂题意,以为是当将要溢出的时候清空,实际上是溢出以后再清空。

#include <map>#include <set>#include <cmath>#include <ctime>#include <queue>#include <stack>#include <string>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;typedef pair<int,int> PII;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1#define bitcnt(x) __builtin_popcount(x)#define bitcntll(x) __builtin_popcountll(x)//#pragma comment(linker, "/STACK:1024000000,1024000000")const int INF = 0x3f3f3f3f;const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;const double ERR = 1e-8;const int MOD = 1e6 + 3;const int MAXN = 1e6 + 50;const int MAXM = 2e5 + 50;int n, b, d, a[MAXN];int main() {#ifdef LOCAL_NORTH    FIN;#endif // LOCAL_NORTH    while (~scanf("%d%d%d", &n, &b, &d)) {        int cnt = 0, tot = 0;        for (int i = 0; i < n; i++ ) {            scanf("%d", &a[i]);            if (a[i] > b)                continue;            if (tot + a[i] > d) {                cnt++;                tot = 0;            } else {                tot += a[i];            }        }        printf("%d\n", cnt);    }#ifdef LOCAL_NORTH    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // LOCAL_NORTH    return 0;}



B. Checkpoints

暴力。输入的时候计算出所有点的坐标减去初始点的坐标,然后排序。显然访问连续n-1个点要走的总距离最小,所以枚举左端点i,计算出右端点i+n-2,计算出初始点访问[i,i+n-2]需要走的距离。(后来才想起来只可能走[1,n-1]和[2,n]两个区间,枚举都不用了。。。

#include <map>#include <set>#include <cmath>#include <ctime>#include <queue>#include <stack>#include <string>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;typedef pair<int,int> PII;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1#define bitcnt(x) __builtin_popcount(x)#define bitcntll(x) __builtin_popcountll(x)//#pragma comment(linker, "/STACK:1024000000,1024000000")const int INF = 0x3f3f3f3f;const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;const double ERR = 1e-8;const int MOD = 1e6 + 3;const int MAXN = 1e6 + 50;const int MAXM = 2e5 + 50;int n, a, loc[MAXN];int main() {#ifdef LOCAL_NORTH    FIN;#endif // LOCAL_NORTH    while (~scanf("%d%d", &n, &a)) {        for (int i = 0; i < n; i++) {            scanf("%d\n", &loc[i]);            loc[i] -= a;        }        sort(loc, loc + n);        LL dis = INFLL;        for (int i = 0; i + n - 2 < n; i++) {            if (loc[i] <= 0 && loc[i + n - 2] <= 0) { //当左右端点都在初始点左边                dis = min(dis, (LL)-loc[i]);            } else if (loc[i] <= 0 && loc[i + n - 2] >= 0) { //在左右两边                dis = min(dis, (LL)min(-loc[i] * 2 + loc[i + n - 2], -loc[i] + loc[i + n - 2] * 2)); //注意要返回,所以乘2            } else if (loc[i] >= 0 && loc[i + n - 2] >= 0) { //都在初始点右边                dis = min(dis, (LL)loc[i + n - 2]);            }        }        printf("%I64d\n", dis);    }#ifdef LOCAL_NORTH    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // LOCAL_NORTH    return 0;}


C. Letters Cyclic Shift

既然要去字典序最小,那么显然是变换一个不包含a的连续区间,直接搞就可以了。注意题目要求至少变换一个字符,所以当字符串全是a时,要把最后一位的a变为z。

#include <map>#include <set>#include <cmath>#include <ctime>#include <queue>#include <stack>#include <string>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;typedef pair<int,int> PII;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1#define bitcnt(x) __builtin_popcount(x)#define bitcntll(x) __builtin_popcountll(x)//#pragma comment(linker, "/STACK:1024000000,1024000000")const int INF = 0x3f3f3f3f;const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;const double ERR = 1e-8;const int MOD = 1e6 + 3;const int MAXN = 1e6 + 50;const int MAXM = 2e5 + 50;string s;int main() {#ifdef LOCAL_NORTH    FIN;#endif // LOCAL_NORTH    while (cin >> s) {        int len = s.size();        bool ok = true;        for (int i = 0; i < len; i++) {            if (ok && s[i] == 'a')                continue;            if (s[i] != 'a') {                s[i]--;                ok = false;            }            else                break;        }        if (ok)            s[len - 1] = 'z';        cout << s << endl;    }#ifdef LOCAL_NORTH    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // LOCAL_NORTH    return 0;}


D. Recover the String

这道题有毒- -

代码写的太乱了,我自己都不想看,说一些思路吧。

题目给出了4个数分别表示原字符串的长度为2的子序列(注意不是子串,不需要连续)的个数,要求还原出字符串。

首先,可以通过a00和a11计算出字符串的0和1的数量(当然计算出的n和m不是整数,就一定是Impossible了),然后就是把n个0和m个1排列组合。

我们可以这样考虑,长度为n,只包含0的字符串,每次插入一个1,那么每次增加的“01”子序列和“10”子序列的总和数一定是n。所以(a01+a10)%n!=0的情况也一定是Impossible。

所以还原字符串就是把1不断地插入到字符串里面。插入的过程就是所有的1都插入到所有的0后面,每插入1个1,“01”子序列的数量就增加n,如果a01%n!=0,那么还需要一个1插入到第(a01%n)个0后面。多余的1全部插入到所有的0前面。

然后就是大量的特判。。。

代码太挫不要看。

#include <map>#include <set>#include <cmath>#include <ctime>#include <queue>#include <stack>#include <string>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;typedef pair<int,int> PII;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1#define bitcnt(x) __builtin_popcount(x)#define bitcntll(x) __builtin_popcountll(x)//#pragma comment(linker, "/STACK:1024000000,1024000000")const int INF = 0x3f3f3f3f;const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;const double ERR = 1e-8;const int MOD = 1e6 + 3;const int MAXN = 1e6 + 50;const int MAXM = 2e5 + 50;LL a00, a01, a10, a11;int main() {#ifdef LOCAL_NORTH    FIN;#endif // LOCAL_NORTH    while (~scanf("%I64d%I64d%I64d%I64d", &a00, &a01, &a10, &a11)) {        LL zero, one;        if (a00 + a01 + a10 + a11 == 0) {            printf("1\n");            continue;        }        if (!a00 || !a11) {            if (!a00 && !a11) {                if ((!a01 && !a10) || (a01 && a10)) {                    printf("Impossible\n");                } else if (a01 <= 1 && !a10) {                    printf("01\n");                } else if (!a01 && a10 <= 1) {                    printf("10\n");                } else {                    printf("Impossible\n");                }            } else if (!a00) {                double t = (1 + sqrt(1 + 8 * a11)) / 2;                if (fabs(t - floor(t)) > ERR) {                    printf("Impossible\n");                    continue;                }                one = (LL)t;                if (a01 + a10) {                    if (a10 + a01 != one) {                        printf("Impossible\n");                    } else {                        for (LL i = 0; i < one; i++) {                            if (i == a10)                                printf("0");                            printf("1");                        }                        if (one == a10) // 0 0 4 6                            printf("0");                        puts("");                    }                } else {                    for (LL i = 0; i < one; i++)                        printf("1");                    puts("");                }            } else {                double t = (1 + sqrt(1 + 8 * a00)) / 2;                if (fabs(t - floor(t)) > ERR) {                    printf("Impossible\n");                    continue;                }                zero = (LL)t;                if (a01 + a10) {                    if (a01 + a10 != zero) {                        printf("Impossible\n");                    } else {                        for (LL i = 0; i < zero; i++) {                            if (i == a01)                                printf("1");                            printf("0");                        }                        if (zero == a01) // 6 4 0 0                            printf("1");                        puts("");                    }                } else {                    for (LL i = 0; i < zero; i++)                        printf("0");                    puts("");                }            }            continue;        }        double t = (1 + sqrt(1 + 8 * a00)) / 2;        if (fabs(t - floor(t)) > ERR) {            printf("Impossible\n");            continue;        }        zero = (LL)t;        t = (1 + sqrt(1 + 8 * a11)) / 2;        if (fabs(t - floor(t)) > ERR) {            printf("Impossible\n");            continue;        }        one = (LL)t;        if ((a01 + a10 == 0) || (a10 + a01) % max(zero, one) || (a01 + a10 > zero * one)) {            printf("Impossible\n");            continue;        }        LL rear, pos = -1, head;        if (zero > one) {            rear = min(one, a01 / zero);            if (a01 % zero)                pos = a01 % zero;            head = one - rear - (pos == -1 ? 0 : 1);            for (LL i = 0; i < head; i++)                printf("1");            for (LL i = 0; i < zero; i++) {                printf("0");                if (pos != -1 && i == pos - 1)                    printf("1");            }            for (LL i = 0; i < rear; i++)                printf("1");        } else {            rear = min(zero, a10 / one);            if (a10 % one)                pos = a10 % one;            head = zero - rear - (pos == -1 ? 0 : 1);            for (LL i = 0; i < head; i++)                printf("0");            for (LL i = 0; i < one; i++) {                printf("1");                if (pos != -1 && i == pos - 1)                    printf("0");            }            for (LL i = 0; i < rear; i++)                printf("0");        }        puts("");    }#ifdef LOCAL_NORTH    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // LOCAL_NORTH    return 0;}


E. Centroids

树形dp。

题目要求判断树上的每一个点,能不能通过至多一次的拆一条边再建一条边(添加之后还是一棵树)操作,使其成为树的重心(树的重心的定义是:以该点为树根,每棵子树的大小都不超过节点数的一半)。

对于一个不是树的重心的节点v,要怎么样操作才能使它成为新树的重心呢?很明显需要在v的节点数大于n/2的子树中,找到一个最大的不超过n/2的子树,把该子树连到v上。这种情况一定是最优的。如果经过一次这样的操作,还有子树大于n/2,那么节点v就要输出0。

所以对于节点v,只需要求出与v相连的子树(v的父节点的不同,详见图E-1)的最大的不超过n/2的子树的大小。具体过程就是3遍dfs。


第一遍dfs,求出每棵子树的大小。

第二遍dfs,求出每棵子树的最大不超过n/2的子树的大小。

第三遍dfs,对于节点v,求出v的父节点pre的不经过v的最大不超过n/2的子树的大小。



(第二、三遍dfs的过程类似于求树的直径,都是利用上一次dfs的结果,来求出v与整棵树的节点的关系)

最后,只需要从1到n枚举v,只要有一棵子树不满足条件,节点v就要输出0(可以理解成:无论怎么拆边与重连,v的某些子树大小都大于n/2)。

#include <map>#include <set>#include <cmath>#include <ctime>#include <queue>#include <stack>#include <string>#include <vector>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;typedef pair<int,int> PII;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1#define bitcnt(x) __builtin_popcount(x)#define bitcntll(x) __builtin_popcountll(x)//#pragma comment(linker, "/STACK:1024000000,1024000000")const int INF = 0x3f3f3f3f;const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;const double ERR = 1e-8;const int MOD = 1e6 + 3;const int MAXN = 4e5 + 50;const int MAXM = 2e5 + 50;int n;struct Edge {    int v, nxt;} E[MAXN << 1];int Head[MAXN], tot;void edge_init() {    tot = 0;    memset(Head, -1, sizeof(Head));}void edge_add(int u, int v) {    E[tot].v = v;    E[tot].nxt = Head[u];    Head[u] = tot++;}int son[MAXN], son_max[MAXN], fa_max[MAXN], par[MAXN];void dfs(int u, int pre) {    son[u] = 1;    par[u] = pre;    for (int i = Head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (v == pre)            continue;        dfs(v, u);        son[u] += son[v];    }}void dfs_down(int u, int pre) {    son_max[u] = (son[u] <= n / 2) ? son[u] : 0;    for (int i = Head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (v == pre)            continue;        dfs_down(v, u);        son_max[u] = max(son_max[u], son_max[v]);    }}void dfs_up(int u, int t, int pre) {    fa_max[u] = max(((n - son[u] <= n / 2) ? (n - son[u]) : 0), t);    int max1 = 0, max2 = 0; //最大值与次大值    for (int i = Head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (v == pre)            continue;        int tmp = son_max[v];        if (tmp >= max1)            swap(max1, tmp);        if (tmp >= max2)            swap(max2, tmp);    }    for (int i = Head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (v == pre)            continue;        if (max1 == son_max[v]) //v的子树与max所记录的子树不是同一棵            dfs_up(v, max(fa_max[u], max2), u);        else            dfs_up(v, max(fa_max[u], max1), u);    }}int main() {#ifdef LOCAL_NORTH    FIN;#endif // LOCAL_NORTH    while (~scanf("%d", &n)) {        edge_init();        for (int i = 0; i < n - 1; i++) {            int u, v;            scanf("%d%d", &u, &v);            edge_add(u, v);            edge_add(v, u);        }        dfs(1, 0);        dfs_down(1, 0);        dfs_up(1, 0, 0);        for (int u = 1; u <= n; u++) {            bool ok = true;            for (int i = Head[u]; ~i; i = E[i].nxt) {                int v = E[i].v;                if (v == par[u]) {                    if (n - son[u] - fa_max[u] > n / 2) {                        ok = false;                        break;                    }                } else {                    if (son[v] - son_max[v] > n / 2) {                        ok = false;                        break;                    }                }            }            printf("%d%c", ok ? 1 : 0, " \n"[u == n]);        }    }#ifdef LOCAL_NORTH    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;#endif // LOCAL_NORTH    return 0;}


0 0
原创粉丝点击