Codeforces Round #607 (Div. 2) 训练总结及A-F题解

A题 :

没什么总结的,就是根据题意去做。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
 
 
int main() {
    IO;
    int t; cin >> t;
    while(t--) {
        string s; cin >> s;
        if(s.back() == 'o') cout << "FILIPINO" << '\n';
        else if(s.back() == 'u') cout << "JAPANESE" << '\n';
        else cout << "KOREAN" << '\n';
    }
    return 0;
}

B题:

题意:两个字符串,问在第一个字符串交换两个字符位置后,能否字典序比第二个字符串小。

做法:贪心,从前到后对每个枚举的字符看后面取后面比他字典序最小的swap。但是如果有多个字典序最小的要取最后一个

总结:wa了一发,wa的地方就在我没取到最后一个。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
 
 
int main() {
    //IO;
    int T;cin >> T;
    while(T--) {
        string s, t; cin >> s >> t;
        forn(i, s.size() - 1) {
            int mi = 27, id = -1;
            for(int j = i + 1; j < s.size(); ++j) {
                int now = s[j] - 'a';
                if(mi >= now) {
                    mi = now;
                    id = j;
                }
            }
            if(s[id] < s[i]) {
                swap(s[id], s[i]);
                break;
            }
        }
        bool ok = 1;
        if(s == t) ok = 0;
        for(int i = 0; i < s.size(); ++i) {
            if(i == t.size()) {
                ok = 0;
                break;
            }
            if(t[i] > s[i]) break;
            else if(t[i] < s[i]) ok = 0;
        }
        if(ok) cout << s << '\n';
        else cout << "---" << '\n';
    }
    return 0;
}

C题:

一道模拟题没什么好说的。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
const int mod = 1e9 + 7;
 
 
int main() {
    IO;
    //freopen("c.in", "r", stdin);
    //freopen("c.txt", "w", stdout);
    int t; cin >> t; while(t--) {
        int op; cin >> op;
        string s; cin >> s;
        ll len = s.size();
        int l = 0;
        bool ok = 0;
        while(s.size() < op) {
            ++l;
            if(l == s.size()) {
                ok = 1;
                break;
            }
            int len = s.size(), now = s[l - 1] - 1 - '0';
            if(!now) continue; 
            string x = s.substr(l);
            //cerr << now << ' ' << l << ' ' << x << ' ' << s << '\n';
            forn(i, now) s += x; 
        }
        if(ok) {
            cout << s.size() << '\n';
            continue;
        }
        l = 0;
        forn(i, op) {
            int x = s[i] - '0';
            ++l;
            len += (x - 1) * ((len - l + mod) % mod);
            len %= mod;
        }
        //forn(i, op) cout << s[i];
        //cout << '\n';
        cout << len << '\n';
    }
    return 0;
}

D题:

题意:不好描述原题中有图例,就好理解了:链接

大概10分钟想到正解,从中间选一个A开始走,只需要4步全图就染A了。所以答案是在0-4之间。然后分类讨论就出来了。(不明白这能有1800分qaq

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
 
const int maxn = 105;
 
int r, c, cnt;
char a[maxn][maxn];
 
inline bool check1() {
    cnt = 0;
    for1(i, r) if(a[i][1] == 'A') ++cnt;
    if(cnt == r) return 1;
    cnt = 0;
    for1(i, r) if(a[i][c] == 'A') ++cnt;
    if(cnt == r) return 1;
    cnt = 0;
    for1(j, c) if(a[1][j] == 'A') ++cnt;
    if(cnt == c) return 1;
    cnt = 0;
    for1(j, c) if(a[r][j] == 'A') ++cnt;
    if(cnt == c) return 1;
    return 0;
}
inline bool check2() {
    if(a[1][1] == 'A' || a[r][1] == 'A' || a[1][c] == 'A' || a[r][c] == 'A') return 1;
    for1(i, r) {
        cnt = 0;
        for1(j, c) if(a[i][j] == 'A') ++cnt;
        if(cnt == c) return 1;
    }
    for1(j, c) {
        cnt = 0;
        for1(i, r) if(a[i][j] == 'A') ++cnt;
        if(cnt == r) return 1;
    }
    return 0;
}
inline bool check3() {
    for1(i, r) {
        if(a[i][1] == 'A') return 1;
        if(a[i][c] == 'A') return 1;
    }
    for1(j, c) {
        if(a[1][j] == 'A') return 1;
        if(a[r][j] == 'A') return 1;
    }
    return 0;
}
 
int main() {
    IO;
    int t; cin >> t;while(t--) {
        cin >> r >> c;
        cnt = 0;
        for1(i, r) for1(j, c) {
            cin >> a[i][j];
            if(a[i][j] == 'A') ++cnt;
        }
        if(cnt == r * c) {
            cout << 0 << '\n';
            continue;
        }
        if(!cnt) {
            cout << "MORTAL" << '\n';
            continue;
        }
        if(check1()) {
            cout << 1 << '\n';
            continue;
        }
        if(check2()) {
            cout << 2 << '\n';
            continue;
        }
        if(check3()) {
            cout << 3 << '\n';
            continue;
        }
        cout << 4 << '\n';
    }
    return 0;
}

E题:

题意:

一棵树,2k个点,带点权。现在有k对情侣,每个人都在点上。一对情侣之间的距离为树上两点的路径长。现在分配这k对情侣,问k对情侣的距离加起来最短的值和最大的值。

做法:

最小值:尽可能选相邻的点,那么我们跑dfs,只要父亲点所连的儿子的子树大小是偶数就代表这颗子树可以内部两两匹配,此外就+=这条边的权值。

最大值:尽可能选择远的点对,但是这个点对不好找,可以算每条边的贡献。u-v的边贡献就是min(sz[v], n - sz[v]) * w,原因是子树的点想往外走,外面的点想往里走(围城qaq)。

然后就做出来

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
const int maxn = 2e5 + 5;
 
ll ans, ans2;
int n;
vector<pair<int, int> >e[maxn];
int sz[maxn];
 
inline void init(int n) {
    ans = ans2 = 0;
    forn(i, n + 5) {
        e[i].clear();
        sz[i] = 0;
    }
}
inline void dfs(int u, int pre) {
    sz[u] = 1;
    for(auto &x : e[u]) {
        int v = x.first, w = x.second;
        if(v == pre) continue;
        dfs(v, u);
        sz[u] += sz[v];
        if(sz[v] & 1) ans += w;
        ans2 += 1ll * min(sz[v], n - sz[v]) * w;
    }
 
}
 
int main() {
    IO;
    int t; cin >> t;
    while(t--) {
        cin >> n;
        n <<= 1;
        forn(i, n - 1) {
            int u, v, w; cin >> u >> v >> w;
            e[u].push_back({v, w});
            e[v].push_back({u, w});
        }
        dfs(1, 1);
        cout << ans << ' ' << ans2 << '\n';  
        init(n);
    } 
    return 0;
}

F题:

题意:一棵树,每个点有两个点权一个正一个负。现在让你分出m个点集,并且这个点集内的任意两点中的路径的点都要在该点集中。这个点集的正权sum和>负权sum和,ans++,问ans最大值多少。

思路:

树上dp,dpij表示第i个点的子树中分出j个点集的ans值以及i点所处点集的权值。做出这个就可以从儿子结点转移到父亲结点。具体写法看代码。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
 
const int inf = 2e9;
const ll INF = 8e18;
const int maxn = 3e3 + 5;
 
int n, m;
int a[maxn], sz[maxn];
pair<int, ll> dp[maxn][maxn], dpp[maxn][maxn];
vector<int>e[maxn];
 
inline void init() {
    forn(i, n + 5) e[i].clear();
}
 
inline void dfs(int u, int pre) {
    sz[u] = 1; dp[u][1] = {0, a[u]};
    for(auto v : e[u]) {
        if(v == pre) continue;
        dfs(v, u);     
        //cerr << "!@#  " << u << ' ' << v << '\n';
        for(int i = 1; i <= sz[u] + sz[v]; ++i) dpp[u][i] = {0, -INF};
        for(int i = 1; i <= sz[u]; ++i) {
            for(int j = 1; j <= sz[v]; ++j) {
               // cerr << dp[u][i].first << ' ' << dp[u][i].second << ' ' << dp[v][j].first << ' ' << dp[v][j].second << '\n';
                dpp[u][i + j] = max(dpp[u][i + j], {dp[u][i].first + dp[v][j].first + (dp[v][j].second > 0), dp[u][i].second});
                dpp[u][i + j - 1] = max(dpp[u][i + j - 1], {dp[u][i].first + dp[v][j].first, dp[v][j].second + dp[u][i].second});
               // cerr << i << ' ' << j << ' ' << dpp[u][i + j].first << ' ' << dpp[u][i + j].second << ' ' << dpp[u][i + j - 1].first << ' ' << dpp[u][i + j - 1].second << '\n';
            }
        }
        for(int i = 1; i <= sz[u] + sz[v]; ++i) dp[u][i] = dpp[u][i];
        sz[u] += sz[v];
    }
}
/*void dfs(int u, int v) {
    cerr << "!@#" << '\n';
}*/
 
int main() {
    IO;
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int t; cin >> t; while(t--) {
        cin >> n >> m;
        for1(i, n) cin >> a[i];
        for1(i, n) {
            int x; cin >> x;
            a[i] = x - a[i];
            //cerr << a[i] << ' ';
        }
        //cerr << '\n';
        forn(i, n - 1) {
            int u, v; cin >> u >> v;
            e[u].push_back(v); e[v].push_back(u);
        }
        dfs(1, 1);
        /*for1(i, n) {
            for1(j, 4) cerr << dp[i][j].first << ' ' << dp[i][j].second << " # "; 
            cerr << '\n';
        }*/
        cout << dp[1][m].first + (dp[1][m].second > 0) << '\n'; 
        init();
    }
    return 0;
}

 

posted @ 2020-03-02 19:13  AlexPanda  阅读(176)  评论(0编辑  收藏  举报