• SDUWHCCCC校内选拔赛题解


    L1-1 宇宙无敌大招呼

    签到

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        string s;
        cin >> s;
        s = "Hello " + s;
        cout << s << "\n";
        return 0;
    }
    

    L1-2 寻找250

    签到

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int x, idx = 0;
        while(cin >> x) {
            idx ++;
            if(x == 250) {
                cout << idx << "\n";
                break;
            }
        }
        return 0;
    }
    

    L1-3 装睡

    签到

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);   
        int n;
        cin >> n;
        while(n -- ) {
            string s;
            int x, y;
            cin >> s >> x >> y;
            if(x < 15 or x > 20 or y < 50 or y > 70) 
                cout << s << "\n"; 
        }
        return 0;
    }
    

    L1-4 生命游戏

    按要求模拟

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    const int dx[] = {0, 0, 1, -1, 1, 1, -1, -1};
    const int dy[] = {-1, 1, 0, 0, -1, 1, -1, 1};
    
    char g[55][55], ng[55][55];
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);   
        int T;
        cin >> T;
        while(T -- ) {
            int n, m;
            cin >> n >> m;
            for(int i = 1; i <= n; ++ i) cin >> (g[i] + 1);
            for(int i = 1; i <= n; ++ i) 
                for(int j = 1; j <= m; ++ j) {
                    int cnt = 0;
                    for(int k = 0; k < 8; ++ k) {
                        int xx = i + dx[k], yy = j + dy[k];
                        if(xx >= 1 and yy >= 1 and xx <= n and yy <= m and g[xx][yy] == '1')
                            cnt ++;
                    }
                    if(g[i][j] == '1') {
                        if(cnt <= 1 or cnt >= 4) ng[i][j] = '0';
                        else ng[i][j] = '1';
                    }
                    else {
                        if(cnt == 3) ng[i][j] = '1';
                        else ng[i][j] = '0';
                    }
                }
            for(int i = 1; i <= n; ++ i)  {  
                for(int j = 1; j <= m; ++ j)
                    cout << ng[i][j];
                cout << "\n";
            }
        }
        return 0;
    }
    

    L1-5 个位数统计

    按要求模拟

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);   
        string s;
        cin >> s;
        map<int, int> mp;
        for(int i = 0; i < s.size(); ++ i) 
            mp[s[i] - '0'] ++;
        for(auto [x, y] : mp)
            cout << x << ":" << y << "\n";
        return 0;
    }
    

    L1-6 整除分块

    考虑\(\left\lfloor\dfrac{n}{i}\right\rfloor\) \((i = 1, 2, ..., n)\) , 该式最多只有 $2 \sqrt n $ 个取值

    • \(i \le \sqrt n\), 最多只有 \(\sqrt n\) 个不同的取值
    • \(i > \sqrt n\), 式子取值从 \(\sqrt n\)\(1\), 最多只有 \(\sqrt n\) 个不同值
      故该式最多只有 \(2\sqrt n\) 个取值

    根据 \(x\) 求最大 \(t\), 使得 \(\left\lfloor\dfrac{n}{x}\right\rfloor = \left\lfloor\dfrac{n}{t}\right\rfloor\)\(\left\lfloor\dfrac{n}{x}\right\rfloor > \left\lfloor\dfrac{n}{t + 1}\right\rfloor\), \(t = \left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{x}\right\rfloor}\right\rfloor\)

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int T;
        cin >> T;
        while(T -- ) {
            int n, x;
            cin >> n >> x;
            vector<int> v;   
            for(int l = 1, r = 0; l <= n; l = r + 1) {
                r = min(n, n / (n / l));
                v.push_back(n / l);
            }
            sort(v.begin(), v.end());
            cout << lower_bound(v.begin(), v.end(), x) - v.begin() + 1 << "\n";
        }   
        return 0;
    }
    

    L1-7 点赞

    按要求模拟

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int n;
        cin >> n;
        map<int, int> mp;
        for(int i = 1, k; i <= n; ++ i) {
            cin >> k;
            for(int j = 0, x; j < k; ++ j) {
                cin >> x;
                mp[x] ++;
            }
        }
        int id = 0;
        for(auto [x, y] : mp) {
            if(y >= mp[id]) id = x;
        }
        cout << id << " " << mp[id] << "\n";
        return 0;
    }
    

    L1-8 古风排版

    先用空格将字符串长度补全至 \(n\) 的整数倍,然后按要求模拟即可

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int n;
        cin >> n;
        string s;
        getline(cin, s);
        getline(cin, s);
        int m = (s.size() + n - 1) / n * n;
        while(s.size() < m) s += " ";
        for(int i = n - 1; i >= 0; -- i) {
            for(int j = s.size() - 1 - i; j >= 0; j -= n) 
                cout << s[j];
            cout << "\n";
        }
        return 0;
    }
    

    L2-1 奥运排行榜

    按照四种关键字排序模拟
    坑点:若四个国家金牌数为 \(4\) \(3\) \(3\) \(2\),排名应该是 \(1\) \(2\) \(2\) \(4\),而不是 \(1\) \(2\) \(2\) \(3\)

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    
    struct Node {
        int a, b, c, id;
    };
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<Node> v(n);
        for(int i = 0; i < n; ++ i) {
            cin >> v[i].a >> v[i].b >> v[i].c;
            v[i].id = i;
        } 
        vector<vector<int>> rk(n, vector<int>(4));
        sort(v.begin(), v.end(), [&](Node x, Node y){
            return x.a > y.a;
        });
        int idx = 1;
        for(int i = 0; i < n; ++ i) {
            if(i and v[i].a != v[i - 1].a) idx = i + 1;
            rk[v[i].id][0] = idx;
        }
        sort(v.begin(), v.end(), [&](Node x, Node y){
            return x.b > y.b;
        });
        idx = 1;
        for(int i = 0; i < n; ++ i) {
            if(i and v[i].b != v[i - 1].b) idx = i + 1;
            rk[v[i].id][1] = idx;
        }
        sort(v.begin(), v.end(), [&](Node x, Node y){
            return x.a * y.c > y.a * x.c;
        });
        idx = 1;
        for(int i = 0; i < n; ++ i) {
            if(i and v[i].a * v[i - 1].c != v[i - 1].a * v[i].c) idx = i + 1;
            rk[v[i].id][2] = idx;
        }
        sort(v.begin(), v.end(), [&](Node x, Node y){
            return x.b * y.c > y.b * x.c;
        });
        idx = 1;
        for(int i = 0; i < n; ++ i) {
            if(i and v[i].b * v[i - 1].c != v[i - 1].b * v[i].c) idx = i + 1;
            rk[v[i].id][3] = idx;
        }
        for(int i = 1; i <= m; ++ i) {
            int x, t = 0;
            cin >> x;
            for(int j = 0; j < 4; ++ j) {
                if(rk[x][j] < rk[x][t])
                    t = j;
            }
            cout << rk[x][t] << ':' << t + 1 << " \n"[i == m];
        }
        return 0;
    }
    

    L2-2 文件传输

    并查集模板题

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        int n;
        cin >> n;
        vector<int> f(n);
        for(int i = 0; i < n; ++ i) f[i] = i;
        function<int(int)> getf = [&](int x) {
            return x == f[x] ? f[x] : f[x] = getf(f[x]);
        };
        char op;
        while(cin >> op) {
            if(op == 'S') {
                int cnt = 0;
                for(int i = 0; i < n; ++ i) cnt += f[i] == i;
                if(cnt == 1) cout << "The network is connected.\n";
                else cout << "There are "<< cnt << " components.\n";
                break;
            }
            int x, y;
            cin >> x >> y;
            x --, y --;
            int fx = getf(x), fy = getf(y);
            if(op == 'I') {
                if(fx != fy) 
                    f[fx] = fy;
            }
            else {
                if(fx == fy) cout << "yes\n";
                else cout << "no\n";
            }
        }
        return 0;
    }
    

    L2-3 功夫传人

    遍历树,统计答案

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    using LL = long long;
    
    int n;
    double ans, z, r;
    vector<int> g[100010], b;
    
    void dfs(int u, double val) {
        if(b[u]) ans += val * b[u];
            else {
                for(auto v : g[u]) dfs(v, val * (100.0 - r) / 100.0); 
            }
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        cin >> n >> z >> r;
        b.resize(n);
        for(int i = 0, k; i < n; ++ i) {
            cin >> k;
            if(not k) cin >> b[i];
            for(int j = 0, x; j < k; ++ j) {
                cin >> x;
                g[i].push_back(x);
            }
        }
        dfs(0, z);
        cout << (LL)ans << "\n";
        return 0; 
    }
    

    L2-4 玩转二叉树

    根据中序遍历和前序遍历建树,按要求层序遍历即可

    Sample Code (C++)
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 10010;
    
    int n, in[N], pre[N], lc[N], rc[N];
    
    int solve(int lin, int rin, int lpre, int rpre) {
        if(lin > rin) return 0;
        int rt = pre[lpre];
        int p = lin;
        while(in[p] != rt) p ++;
        lc[rt] = solve(lin, p - 1, lpre + 1, lpre + p - lin);
        rc[rt] = solve(p + 1, rin, lpre + p - lin + 1, rpre);
        return rt;
    }
    
    vector<int> p[32];
    
    void dfs(int u, int dep) {
        p[dep].push_back(u);
        if(lc[u]) dfs(lc[u], dep + 1);
        if(rc[u]) dfs(rc[u], dep + 1);
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        cin >> n;
        for(int i = 0; i < n; ++ i) cin >> in[i];
        for(int i = 0; i < n; ++ i) cin >> pre[i];
        solve(0, n - 1, 0, n - 1);
        dfs(pre[0], 0);
        int cnt = 0;
        for(int i = 0; i < 30; ++ i) {
            reverse(p[i].begin(), p[i].end());
            for(int j = 0; j < p[i].size(); ++ j) {
                cnt ++;
                cout << p[i][j] << " \n"[cnt == n];
            }
        }
        return 0;
    }
    

    L3-1 森森旅游

    先预处理从 \(1\)\(n\) 出发的花费,即在原图 \(G\) 上从起点 \(1\) 以现金为边权跑一遍 \(dijkstra\), 将原图的边反向建图得到 \(rG\), 在 \(rG\) 上从终点 \(n\) 以旅游金为边权跑一遍 \(dijkstra\), 然后用一个 \(multiset\) 维护在 \(n\) 个城市兑换旅游金的现金花费,可以支持动态修改,且可以取最小值

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100010;
    using PII = pair<int, int>;
    using LL = long long;
    using PLI = pair<LL, int>;
    const LL INF = 1e18;
    
    vector<PII> G[N], rG[N];
    int n, m, q, a[N];
    LL dis[N], rdis[N], res[N];
    bool st[N];
    
    void dijkstra(int S, LL dis[], int op) {
        for(int i = 1; i <= n; ++ i) {
            dis[i] = INF;
            st[i] = false;
        }
        priority_queue<PLI, vector<PLI>, greater<PLI>> Q;
        Q.push({0, S});
        dis[S] = 0;
        while(!Q.empty()) {
            int u = Q.top().second;
            Q.pop();
            if(st[u]) continue;
            st[u] = true;
            if(op) {
                for(auto &[v, w] : G[u]) 
                    if(dis[v] > dis[u] + w) {
                        dis[v] = dis[u] + w;
                        Q.push({dis[v], v});
                    }
            }
            else {
                for(auto &[v, w] : rG[u]) {
                    if(dis[v] > dis[u] + w) {
                        dis[v] = dis[u] + w;
                        Q.push({dis[v], v});
                    }
                }
            }
        }
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        cin >> n >> m >> q;
        for(int i = 0; i < m; ++ i) {
            int u, v, c, d;
            cin >> u >> v >> c >> d;
            G[u].push_back({v, c});
            rG[v].push_back({u, d});
        }
        for(int i = 1; i <= n; ++ i) cin >> a[i];
        dijkstra(1, dis, 1);
        dijkstra(n, rdis, 0);
        multiset<LL> S;
        for(int i = 1; i <= n; ++ i) {
            if(dis[i] == INF or rdis[i] == INF) continue;
            res[i] = dis[i] + (rdis[i] + a[i] - 1) / a[i];
            S.insert(res[i]);
        }
        while(q -- ) {
            int x, v;
            cin >> x >> v;
            if(dis[x] != INF and rdis[x] != INF) { 
                auto it = S.find(res[x]);
                S.erase(it);
                res[x] = dis[x] + (rdis[x] + v - 1) / v;
                S.insert(res[x]);
            }
            cout << *S.begin() << "\n";
        }
        return 0; 
    }
    

    L3-2 至多删三个字符

    \(dp[i][j]\) 为前 \(i\) 个字符删除了 \(j\) 个,得到不同字符串的个数
    首先考虑一个简单问题,不考虑删除字符后得到字符串的重复
    那么有状态转移方程: \(dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]\)
    现在考虑如何去重,例如串 \(******a**a***\),设第一个 'a' 的位置为 \(k\), 第二个 'a' 的位置为 \(i\)
    当我们删除从 \(k\) 开始的 \(a**\) 和 删除到 \(i\) 结束的 \(**a\) 时,得到的字符串相同,需要去重的情况是第一个 'a' 字符前面(即 \(k - 1\)) 去除 \(i - 3\) 个字符的情况,即为 \(dp[k - 1][j - (i - k)]\),故当出现相同字符时按照上述去重方式去重即可

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    using LL = long long;
    const int N = 1000010;
    
    LL dp[N][4];
    char s[N];
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
        cin >> (s + 1);
        int n = strlen(s + 1);
        dp[0][0] = 1;
        for(int i = 1; i <= n; ++ i)
            for(int j = 0; j <= 3; ++ j) {
                if(i < j) continue;
                dp[i][j] = dp[i - 1][j];
                if(j >= 1) dp[i][j] += dp[i - 1][j - 1];
                for(int k = i - 1; k >= 1 && i - k <= j; -- k) 
                    if(s[i] == s[k]) {
                        dp[i][j] -= dp[k - 1][j - (i - k)]; 
                        break;
                    }
            }
        LL res = 0;
        for(int i = 0; i <= 3; ++ i) res += dp[n][i];
        cout << res << "\n";
        return 0;
            
    }
    

    L3-3 胜利者集合

    首先枚举每一个玩家 \(x\) 是否可以成为胜利者,当对一个玩家进行判断时,他的胜场应尽可能多,那么他还未进行的比赛将全部获胜。
    此时假设他的胜场为 \(win\), 于是问题转化为当其他人的胜场最大为 \(win - 1\) 的情况下,是否可以构造出一种合法方案?
    对于上述问题,可以转化为一个最大流的问题,考虑如何建图:

    • 建立两组点,第一组点是比赛(除去与 \(x\) 进行的比赛),第二组点是玩家(除去 \(x\)),流量即为胜利
    • 从源点 \(S\) 向所有比赛连接一条容量为 \(1\) 的边
    • 若当前比赛未比,则从当前比赛到两个玩家各连一条容量为 \(1\) 的边
    • 若当前比赛已比,则从当前比赛到胜者连一条容量为 \(1\) 的边
    • 若某玩家胜过 \(x\),则从当前玩家向汇点 \(T\) 连一条容量为 \(win - 2\) 的边
    • 若某玩家输给 \(x\),则从当前玩家向汇点 \(T\) 连一条容量为 \(win - 1\) 的边

    判断最大流是否满流,若满流,则存在一种合法方案,即该玩家 \(x\) 可以成为胜利者

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1500, M = 10010, INF = 1e9;
    
    int n, m, S, T;
    struct Edge {
        int to, nxt, flow;
    }line[M];
    int fist[N], idx, d[N], cur[N];
    
    void add(int x, int y, int z) {
        line[idx] = {y, fist[x], z}; fist[x] = idx ++;
        line[idx] = {x, fist[y], 0}; fist[y] = idx ++;
    }
    
    bool bfs() {
        queue<int> q;
        memset(d, -1, sizeof d);    
        q.push(S), d[S] = 0, cur[S] = fist[S];
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int i = fist[u]; i != -1; i = line[i].nxt) {
                int v = line[i].to;
                if(d[v] == -1 && line[i].flow) {
                    d[v] = d[u] + 1;
                    cur[v] = fist[v];
                    if(v == T) return 1;
                    q.push(v); 
                }
            }
        }
        return 0;
    }
    
    int find(int u, int limit) {
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; i != -1 && flow < limit; i = line[i].nxt) {
            cur[u] = i;
            int v = line[i].to;
            if(d[v] == d[u] + 1 && line[i].flow) {
                int t = find(v, min(line[i].flow, limit - flow));
                if(!t) d[v] = -1;
                line[i].flow -= t;
                line[i ^ 1].flow += t;
                flow += t;
            }
        }
        return flow;
    }
    
    int dinic() {
        int res = 0, flow;
        while(bfs()) while(flow = find(S, INF)) res += flow;
        return res;
    }
    
    int main() {
        ios::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);
        cin >> n >> m;
        vector<vector<int>> g(n, vector<int>(n, 0));
        for(int i = 0; i < m; ++ i) {
            int u, v;
            cin >> u >> v;
            u --, v --;
            g[u][v] = 1, g[v][u] = -1;
        }
        S = n + (n - 2) * (n - 1) / 2;
        T = S + 1;
        int flag = 0;
        for(int i = 0; i < n; ++ i) {
            int win = n - 1;
            for(int j = 0; j < n; ++ j) 
                if(g[i][j] == -1) win --;
            idx = 0;
            memset(fist, -1, sizeof fist);
            int cur = n;
            for(int j = 0; j < n; ++ j) {
                if(j == i) continue;
                for(int k = j + 1; k < n; ++ k) {
                    if(k == i) continue;
                    add(S, cur, 1);
                    if(g[j][k] == 0) {
                        add(cur, j, 1);
                        add(cur, k, 1);
                    }
                    if(g[j][k] == 1)
                        add(cur, j, 1);
                    if(g[j][k] == -1)
                        add(cur, k, 1);
                    cur ++;
                }
            }
            bool ok = true;
            for(int j = 0; j < n; ++ j) {
                if(win - 1 - (g[j][i] > 0) < 0) {
                    ok = false;
                    break;
                }
                if(j != i) 
                    add(j, T, win - 1 - (g[j][i] > 0));
            }
            if(!ok) continue;
            if(dinic() == (n - 1) * (n - 2) / 2) {
                if(flag) cout << ' ';
                cout << i + 1;
                flag = 1;
            }
        }
        cout << '\n';
        return 0;
    }
    
  • 相关阅读:
    js弹出文字
    javascript函数的使用
    php笔记-双引号内的变量会被解释,而单引号内的变量则原样输出
    单独编译源码树下的模块
    内核模块开机自动加载和黑名单
    [转]Linux中设置服务自启动的三种方式
    rpm打包
    APC to USB
    [转]创建一个虚拟盘
    编译打印输出重定向
  • 原文地址:https://www.cnblogs.com/ooctober/p/16022055.html
Copyright © 2020-2023  润新知