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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值