Codeforces Round #375 (Div. 2) ABCDEF题解

A. The New Year: Meeting Friends

同一直线上的三个人要集合,求三个人一共走的距离的最小值。

max(a, b, c) - min(a, b, c)

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e4 + 50;
const int MAXM = 1e4 + 50;

int a, b, c;

int main() {
#ifdef LOCAL_NORTH
//    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d%d", &a, &b, &c)) {
        printf("%d\n", max(a, max(b, c)) - min(a, min(b, c)));
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

B. Text Document Analysis

输出括号外的单词的最大长度已经括号内单词的个数。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e4 + 50;
const int MAXM = 1e4 + 50;

int n;
string s;

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (cin >> n >> s) {
        int ans1 = 0, ans2 = 0, len = 0, in = 0;
        for (int i = 0; i < n; i++) {
            if (isalpha(s[i])) len++;
            else {
                if (!in) ans1 = max(ans1, len);
                else if (len) ans2++;
                len = 0;
                if (s[i] == '(' || s[i] == ')') in = 1 - in;
            }
        }
        ans1 = max(ans1, len);
        printf("%d %d\n", ans1, ans2);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

C. Polycarp at the Radio

有n首曲子明天要演奏,一个人希望他喜欢的m个乐队演奏的歌曲数的最大值最小。输出改变次数最少的演奏安排。

目的是使m个乐队至少演奏n/m首。

统计一下原来这m个乐队演奏的数目并排序。目的是使原本歌曲数多的演奏n/m+1首或n/m首(根据原本的次数判断一下改变后按演奏多少),原本少的演奏n/m首。这样一来,改变的次数就必定最小。

计算出为符合要求,乐队i需要增加或减少的歌曲数op[i]。这时op数组有正有负,来一次n^2的操作把所有的负数消掉,即找到op[i] < 0,op[j] > 0,然后op[i]++,op[j]--。

最后遍历整个序列,把大于m的乐队变为小于等于m的乐队。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e3 + 50;
const int MAXM = 1e4 + 50;

int m, n, a[MAXN], op[MAXN], c[MAXN];
struct node{
    int c, id;
    node(int _c, int _id) {c = _c; id = _id;}
    bool operator < (const node& _) const {return c > _.c;}
};

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &m)) {
        memset(c, 0, sizeof(c));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            if (a[i] >= 1 && a[i] <= m) c[a[i]]++;
        }
        vector<node> v;
        for (int i = 1; i <= m; i++) v.pb(node(c[i], i));
        sort(v.begin(), v.end());
        int ans1 = n / m, ans2 = 0;
//        for (int i = 0; i < m; i++) printf("[%d]%c", v[i].c, " \n"[i == m - 1]);
        int fck = n % m;
        for (int i = 0; i < m; i++) {
            int id = v[i].id;
            op[id] = n / m - c[id];
            while (fck && op[id] <= -1) {
                op[id]++;
                fck--;
            }
            ans2 += abs(op[id]);
        }
//        for (int i = 1; i <= m; i++) printf("%d%c", op[i], " \n"[i == m]);
        for (int i = 1; i <= m; i++) {
            while (op[i] < 0) {
                int s = -1;
                for (int j = 1; j <= m; j++) {
                    if (op[j] > 0) {
                        s = j;
                        break;
                    }
                }
                for (int j = 1; j <= n; j++) {
                    if (a[j] == i) {
                        a[j] = s;
                        op[i]++;
                        op[s]--;
                        ans2--;
                        break;
                    }
                }
            }
        }
        printf("%d %d\n", ans1, ans2);
        for (int i = 1; i <= n; i++) {
            if (a[i] < 1 || a[i] > m) {
                for (int j = 1; j <= m; j++) {
                    if (op[j] > 0) {
                        op[j]--;
                        a[i] = j;
                        break;
                    }
                }
            }
            printf("%d%c", a[i], " \n"[i == n]);
        }
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

D. Lakes in Berland

把最少的水地变为土地,使得湖(连通块)的数目等于k。

bfs一遍统计出湖的个数、每个湖的大小以及湖的任意一点。

排序后,从每个湖中的点开始,把前tot-k个湖变为土地。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 100 + 50;
const int MAXM = 1e4 + 50;

int n, m, k, d[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
char p[MAXN][MAXN];
bool vis[MAXN][MAXN];
struct node{
    int x, y, c;
    bool operator < (const node& _) const {return c < _.c;}
}lakes[MAXN * MAXN];

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d%d", &n, &m, &k)) {
        memset(vis, false, sizeof(vis));
        for (int i = 1; i <= n; i++) scanf("%s", p[i] + 1);
        int tot = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (p[i][j] == '.' && !vis[i][j]) {
                    bool ok = true;
                    int cnt = 0;
                    queue<PII > q;
                    q.push(mp(i, j));
                    vis[i][j] = true;
                    while (!q.empty()) {
                        PII cur = q.front();
                        q.pop();
                        int x = cur.first, y = cur.second;
                        cnt++;
                        if (x < 1 || x > n || y < 1 || y > m) {
                            ok = false;
                            continue;
                        }
                        for (int l = 0; l < 4; l++) {
                            int xx = x + d[l][0], yy = y + d[l][1];
                            if (xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= m + 1 && !vis[xx][yy] && p[xx][yy] != '*')
                                q.push(mp(xx, yy));
                                vis[xx][yy] = true;
                        }
                    }
                    if (ok) {
                        lakes[tot].c = cnt;
                        lakes[tot].x = i;
                        lakes[tot++].y = j;
                    }
                }
            }
        }
        sort(lakes, lakes + tot);
        int ans = 0;
        for (int i = 0; i < tot - k; i++) {
            ans += lakes[i].c;
            queue<PII > q;
            q.push(mp(lakes[i].x, lakes[i].y));
            p[lakes[i].x][lakes[i].y] = '*';
            while (!q.empty()) {
                PII cur = q.front();
                q.pop();
                int x = cur.first, y = cur.second;
                for (int j = 0; j < 4; j++) {
                    int xx = x + d[j][0], yy = y + d[j][1];
                    if (xx > 0 && xx <= n && yy > 0 && yy <= m && p[xx][yy] != '*') {
                        p[xx][yy] = '*';
                        q.push(mp(xx, yy));
                    }
                }
            }
        }
        printf("%d\n", ans);
        for (int i = 1; i <= n; i++) printf("%s\n", p[i] + 1);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

E. One-Way Reform

把无向图转化为有向图,同时使得出度等于入度的点最多。并打印边。

为了使出度等于入度的点最多,要把原图转化为欧拉图,操作为:原图中奇数度的点一定有偶数个,所有将度为奇数的点两两(不是点i与所有的奇数度点连边,而是点i与任意一奇数度点相连)之间加一条边。

然后用Fleury打印欧拉回路即可,注意添加的边不要打印。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 50;
const int MAXM = 1e5 + 50;

int n, m, d[MAXN];
bool vis[MAXN];
struct Edge{
    int v, f, p, nxt;
} E[MAXM << 1];
int tot, Head[MAXN];
void edge_init() {
    tot = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int p) {
    E[tot].v = v; E[tot].f = 0; E[tot].p = p; E[tot].nxt = Head[u]; Head[u] = tot++;
    E[tot].v = u; E[tot].f = 0; E[tot].p = p; E[tot].nxt = Head[v]; Head[v] = tot++;
}

vector<int> odd;
void dfs(int u) {
    vis[u] = true;
    for (int i = Head[u]; ~i; i = E[i].nxt) {
        if (E[i | 1].f) continue;
        E[i | 1].f = 1;
        if (E[i].p) printf("%d %d\n", u, E[i].v);
        dfs(E[i].v);
//        return; !!!!
    }
}

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    int T;
    scanf("%d", &T);
    while (T--) {
        memset(d, 0, sizeof(d));
        memset(vis, false, sizeof(vis));
        odd.clear();
        edge_init();
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            edge_add(u, v, 1);
            d[u]++;
            d[v]++;
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
            if (d[i] & 1) odd.pb(i);
            else ans++;
        for (int i = 0, sz = odd.size(); i < sz - 1; i += 2)
            edge_add(odd[i], odd[i + 1], 0);
        printf("%d\n", ans);
        for (int i = 1; i <= n; i++)
            if (!vis[i])
                dfs(i);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

F. st-Spanning Tree

在原图的基础上构建一棵生成树,同时s的度不大于ds,t的度不大于dt,并打印边。

为了使和s、t相连的边数最少,需要在去掉s和t的每个连通分量内构建一棵生成树。

然后把所有生成树连到s和t上。需要注意不是随便连,否则会出现一个连通分量既可以连到s,也可以连到t,但最后连错导致s和t度数错误。一种可行的方法是每次遇到上文描述的情况,将生成树连到距离度数限制较大的点上。

经过上一步,原图已经变成了两棵生成树,同时注意到图中没有被选中用来构建生成树的边只有3种:

1)端点为s和t;2)一端为s,另一端不为t;3)一端为t,另一端不为s。

现在只需要在一棵生成树上找到任意一条连上后符合题意的边。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#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 lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e5 + 50;
const int MAXM = 4e5 + 50;

int n, m, s, t, ds, dt;
struct Edge{
    int u, v;
}E[MAXM];

int par[MAXN];
int Find(int x) {return par[x] == x ? x : par[x] = Find(par[x]);}
void unite(int a, int b) {
    int x = Find(a), y = Find(b);
    if (x != y) par[x] = y;
}

vector<PII > ans;
bool link[MAXN][2];
int STlink[MAXN], dus, dut;
bool ST2S[MAXN], ST2T[MAXN];
void solveST() {
    for (int i = 0; i < m; i++) {
        int u = E[i].u, v = E[i].v;
        if (u == s || u == t || v == s || v == t)
            continue;
        if (Find(u) != Find(v)) {
            unite(u, v);
            ans.pb(mp(u, v));
        }
    }
    memset(ST2S, false, sizeof(ST2S));
    memset(ST2T, false, sizeof(ST2T));
    for (int i = 1; i <= n; i++) {
        if (i == s || i == t) continue;
        if (link[i][0])
            ST2S[Find(i)] = true;
        if (link[i][1])
            ST2T[Find(i)] = true;
    }
}
void linkST() {
    dus = dut = 0;
    memset(STlink, -1, sizeof(STlink));
    for (int i = 1; i <= n; i++) {
        if (i == s || i == t) continue;
        int stNo = Find(i);
        if (STlink[stNo] != -1) continue;
        bool ok1 = (ST2S[stNo] && dus < ds && link[i][0]);
        bool ok2 = (ST2T[stNo] && dut < dt && link[i][1]);
        int tmp = -1;
        if (ok1 && ok2) {
            if (ds - dus > dt - dut) tmp = s;
            else tmp = t;
        } else if (ok1) tmp = s;
        else if (ok2) tmp = t;
        if (tmp == s) {
            STlink[stNo] = 0;
            unite(i, s);
            ans.pb(mp(i, s));
            dus++;
        } else if (tmp == t) {
            STlink[stNo] = 1;
            unite(i, t);
            ans.pb(mp(i, t));
            dut++;
        }
    }
}
bool Link() {
    if (dus < ds && dut < dt && link[t][0]) {
        dut++, dus++;
        ans.pb(mp(s, t));
        unite(s, t);
        return true;
    }
    for (int i = 1; i <= n; i++) {
        if (i == s || i == t) continue;
        if (Find(i) == Find(s)) {
            if (dut < dt && link[i][1]) {
                dut++;
                ans.pb(mp(t, i));
                unite(i, t);
                return true;
            }
        } else if (Find(i) == Find(t)) {
            if (dus < ds && link[i][0]) {
                dus++;
                ans.pb(mp(s, i));
                unite(i, s);
                return true;
            }
        }
    }
    return false;
}

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &m)) {
        ans.clear();
        memset(link, false, sizeof(link)); //link[i][0]表示是i否与s相连,link[i][1]表示i是否与t相连。
        for (int i = 1; i <= n; i++) par[i] = i;
        for (int i = 0; i < m; i++)
            scanf("%d%d", &E[i].u, &E[i].v);
        scanf("%d%d%d%d", &s, &t, &ds, &dt);
        for (int i = 0; i < m; i++) {
            if (E[i].u == s || E[i].v == s)
                link[E[i].u + E[i].v - s][0] = true;
            if (E[i].u == t || E[i].v == t)
                link[E[i].u + E[i].v - t][1] = true;
        }
        link[s][0] = link[t][1] = true;
        solveST(); //构建生成树
        linkST(); //生成树连向s和t
        if (dus > ds || dut > dt) {
            printf("No\n");
            continue;
        }
        bool ok = Link(); //两棵生成树相连
        for (int i = 1; i <= n; i++)
            ok &= (Find(i) == Find(1));
        if (!ok) {
            printf("No\n");
            continue;
        }
        if (dus <= ds && dut <= dt) {
            printf("Yes\n");
            int sz = ans.size();
            for (int i = 0; i < sz; i++)
                printf("%d %d\n", ans[i].first, ans[i].second);
        } else printf("No\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、付费专栏及课程。

余额充值