AIM Tech Round 3 (Div. 2) (B C D E) (codeforces 709B 709C 709D 709E)

rating又掉下去了。好不容易蓝了。。。。

 

A。。没读懂题,wa了好几次,明天问队友补上。。。

B. Checkpoints

题意:一条直线上n个点x1,x2...xn,现在在位置a,求要经过任意n-1个点的最小路程

题解:分类讨论,乱搞搞总会出来的,我大概写的很笨……

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

int x[100005];

ll cal(ll x, ll a, ll z) {
    return min((a-x)*2+(z-a) , (z-a)*2+(a-x));
}

int main() {
    int n, a;
    scanf("%d%d", &n, &a);
    for (int i = 0; i < n; ++i) {
        scanf("%d", x+i);
    }
    sort(x, x+n);
    ll ans = 1e18, tmp;

    if (n == 1) cout << 0;
    else if (n == 2) cout << min(abs(a-x[0]), abs(a-x[1]));
    else if (a >= x[n-1]) cout << a-x[1];
    else if (a <= x[0]) cout << x[n-2]-a;
    else if (a <= x[1]) cout << min(cal(x[0], a, x[n-2]), (ll)(x[n-1]-a));
    else if (a > x[n-2]) cout << min(cal(x[1], a, x[n-1]), (ll)(a-x[0]));
    else cout << min(cal(x[0],a,x[n-2]), cal(x[1],a,x[n-1]));
    return 0;
}

 

C. Letters Cyclic Shift

题意:给一个字符串,要求替换任意一个非空字串,使得替换后字串字典序最小。替换的方法是z->y,y->x,....,b->a,a->z

题解:C题怎么会这么简单。。。很容易想到替换尽可能靠前的字符,而且不能替换a,注意题目要求的必须替换一个字串,所以字串中所有字母都是a的时候,只能把最后一个变成z了。

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

char a[100005];
int main() {
    while (cin >> a) {
        bool fg = false;
        int n = strlen(a);
        int cnt = 0;
        for (int i = 0; i < n; ++i) {
            if (a[i] != 'a') {a[i]--; fg=true;}
            else if(fg) break;
        }
        if (!fg) a[n-1] = 'z';
        cout << a << endl;
    }

    return 0;
}

 

D. Recover the String

题意:对于一个只有0和1的序列,会有很多00,01,10,11的子序列,现在给你00,01,10,11的子序列的数量,求符合要求的子串,没有输出Impossible

题解:注意,子序列不同于子串,不连续。

设子串中0的数量是x,那么00的数量一定是C(2,x),1同理。然后设0的数量是x,1的数量是y,所以所有子序列的个数是C(2,x+y),即C(2,x+y)==a+b+c+d,如果不相等则不可能构成。要注意的地方是当00的数量为0的时候,x既可以为0,也可以为1,需要根据bc判断。y同理。

至于字符串的构造,有点贪心的想法。瞎搞的。。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char ans[1000005];
int main() {
    ll a, b, c, d;
    while (cin >> a >> b >> c >> d) {
        ll x = (ll)sqrt(a*2)+1;
        ll y = (ll)sqrt(d*2)+1;
        if (a+b+c+d == 0) {
            puts("0");
            continue;
        }
        if (a == 0) {
            if (b || c) x = 1; else x = 0;
        }
        if (d == 0) {
            if (b || c) y = 1; else y = 0;
        }
        if (!(x*(x-1) == a*2 && y*(y-1) == d*2)) {
            puts("Impossible");
            continue;
        }
        ll n = x+y;
        ll xnt = n*(n-1)/2-a-d;
        if (b+c != xnt) {
            puts("Impossible");
            continue;
        }
        int idx = 0;
        int cnt = x+y;
        while (cnt) {
            if (b < y) {
                ans[idx++] = '1';
                c -= x;
                y--;
            } else if (c < x) {
                ans[idx++] = '0';
                b -= y;
                x--;
            } else if (b >= c) {
                ans[idx++] = '0';
                b -= y;
                x--;
            } else {
                ans[idx++] = '1';
                c -= x;
                y--;
            }
            cnt--;
        }
        ans[idx] = 0;
        printf("%s\n", ans);
    }
    return 0;
}

 

 

E. Centroids

题意:给一棵树,对于每一个结点,可不可以通过在树上去掉一条边再增加一条边(必须还是一棵树),使这个结点成为这棵树的重心。
题解:%%%明神

对于一个点,如果不能当重心,一定是它有一棵子树u,size[u]>n/2,那么只要在这个子树u中找到一个子树v,满足size[v]<=n/2且size[u]-size[v]<=n/2就可以了。

于是树形dp,求每个点的<=n/2的最大子树的大小。

至于向上思想类似,随便搞搞,具体看代码。

不喜欢用邻接表存图,看起来很麻烦,可是vector确实会慢一些,比赛一定不能用=。=

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 400005;

vector<int> g[N];
int sz[N], up[N], dn[N]; // up向上的最大的不大于n/2的子树大小 dn向下的
int ans[N];
int n;

inline int read()
{
    char ch = getchar();
    int data = 0;
    while (ch < '0' || ch > '9')
        ch = getchar();
    do {
        data = data*10 + ch-'0';
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    return data;
}

void UP(int &x, int y) { if(y>x) x=y; }
void dfs(int u, int fa) { // 第一遍向下dfs
    sz[u] = 1;
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if (v == fa) continue;
        dfs(v, u);
        if (sz[v] - dn[v] > n/2) ans[u] = 0;
        sz[u] += sz[v];
        UP(dn[u], dn[v]);
    }
    if (sz[u] <= n/2) dn[u] = sz[u];
}
void dfs1(int u, int fa) { // 第二遍向上
    if (n-sz[u] - up[u] > n/2) ans[u] = 0;
    if (n-sz[u] <= n/2) up[u] = n-sz[u];

    int mx = 0; // 对于每一个结点向上的最大值 可能来自向上的链 也可能来自父节点的其他子树
    // mx记录的就父节点其他子树的最大值
    for (int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if (v == fa) continue;
        up[v] = max(up[u], mx);
        UP(mx, dn[v]);
    }
    mx = 0;
    for (int i = g[u].size()-1; i >= 0; --i) {
        int v = g[u][i];
        if (v == fa) continue;
        UP(up[v], mx);
        UP(mx, dn[v]);
        dfs1(v, u);
    }
}

int main() {
    scanf("%d", &n);
    int u, v;
    for (int i = 1; i < n; ++i) {
        u = read(); v = read();
        g[u].push_back(v);
        g[v].push_back(u);
    }
    if (n == 2) { printf("1 1"); return 0; }

    for (int i = 1; i <= n; ++i) ans[i] = 1;
    dfs(1, 0);
    dfs1(1, 0);
    for (int i = 1; i <= n; ++i) {
        printf("%d", ans[i]);
        if (i != n) printf(" ");
    }
    return 0;
}

 

posted @ 2016-08-25 21:50  我不吃饼干呀  阅读(349)  评论(0编辑  收藏  举报