zoukankan      html  css  js  c++  java
  • 2020 Multi-University Training Contest 5

    Contest Info


    传送门

    Solved A B C D E F G H I J K L M
    6 / 13 O - O - - - Ø Ø O - - Ø -
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    A. Tetrahedron

    签到。

    C. Boring Game

    找到规律后直接模拟即可。
    规律是多种多样的。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/04 13:57:50
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef vector<vector<int>> mytype;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = 1e6 + 5;
    
    int n, k;
    int p[N];
    
    mytype cz(vector<int>& a, vector<int>&b, int Max) {
        mytype res;
        vector<int> t1 = b, t2 = a;
        for (int i = 0; i < 2 * n; i++) {
            a[i] += Max;
            b[i] += Max;
        }
        res.push_back(a);
        res.push_back(t1);
        res.push_back(t2);
        res.push_back(b);
        return res;
    }
    
    void gao(mytype& a, int k, int Max) {
        if (k == 0) return;
        vector<mytype> res;
        for (int i = 0; i < sz(a); i += 2) {
            res.push_back(cz(a[i], a[i + 1], Max));
        }
        a.clear();
        for (auto& it : res) {
            for (auto& it2 : it) {
                a.push_back(it2);
            }
        }
        gao(a, k - 1, Max * 2);
    }
    
    void run() {
        cin >> n >> k;
        int tot = 2 * n;
        for (int i = 1; i <= k; i++) {
            tot *= 2;
        }
        for (int i = 1; i <= tot; i++) {
            cin >> p[i];
        }
        mytype a;
        a.resize(2);
        a[0].resize(2 * n), a[1].resize(2 * n);
        for (int i = 0; i < 2 * n; i++) {
            a[0][i] = 2 * n - i;
            a[1][i] = 2 * n + 1 + i;
        }
        --k;
        gao(a, k, 4 * n);
        for (int i = 0; i < 2 * n; i++) {
            for (int j = 0; j < sz(a); j++) {
                cout << p[a[j][i]];
                if (--tot > 0) {
                    cout << ' ';
                }
            }
        }
        cout << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0); 
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    G. Tree

    与选择边数有关的树形(dp),一般的写法就是一开始钦定与父亲连着的拿一条边要选,这样方便转移。最后统计答案断开这条边即可。
    这个题设(dp[i][0/1])表示以(i)为根节点的子树中,是否存在一个点其度数不受到限制,并且(i)与其父亲这条边已选的最大边权和。
    那么最后的答案就是(dp[i][1])断开父亲这条边的最大值,但是注意与父亲断开过后可能还能够多选择一个儿子,这种情况再单独考虑一下即可。
    因为dp转移时要贪心进行转移,所以代码有点细节:

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/04 19:16:59
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = 1e5 + 5;
    void run() {
        int n, k;
        cin >> n >> k;
        vector<vector<pii>> G(n);
        vector<int> d(n);
        ll sum = 0;
        for (int i = 0; i < n - 1; i++) {
            int u, v, w;
            cin >> u >> v >> w;
            sum += w;
            --u, --v;
            G[u].push_back(MP(v, w));
            G[v].push_back(MP(u, w));
            ++d[u], ++d[v];
        }
        if (*max_element(all(d)) <= k) {
            cout << sum << '
    ';
            return;
        }
        if (k == 0) {
            cout << 0 << '
    ';
            return;
        }
        if (k == 1) {
            ll ans = 0;
            for (int i = 0; i < n; i++) {
                ll res = 0;
                for (auto it : G[i]) {
                    int v = it.fi, w = it.se;
                    res += w;
                }
                ans = max(ans, res);
            }
            cout << ans << '
    ';
            return;
        }
    
        vector<vector<ll>> dp(n, vector<ll>(2));
    
        function<ll(int, int, int)> calc = [&](int u, int c, int fa) {
            vector<pair<ll, pair<int, int>>> dp0;
            for (auto it : G[u]) {
                int v = it.fi, w = it.se;
                if (v != fa) {
                    dp0.push_back(MP(dp[v][0] + w, MP(v, w)));
                }
            }
            sort(dp0.rbegin(), dp0.rend());
            ll res = 0, Max = -1e18;
            for (int i = 0; i < min(sz(dp0), c); i++) {
                res += dp0[i].fi;
            }
            for (int i = c; i < sz(dp0); i++) {
                int v = dp0[i].se.fi, w = dp0[i].se.se;
                Max = max(Max, dp[v][1] + w);
            }
            if (sz(dp0) >= c + 1) {
                for (int i = 0; i < c; i++) {
                    int v = dp0[i].se.fi;
                    Max = max(Max, -dp[v][0] + dp[v][1] + dp0[c].fi);
                }
            } else {
                for (int i = 0; i < sz(dp0); i++) {
                    int v = dp0[i].se.fi;
                    Max = max(Max, -dp[v][0] + dp[v][1]);
                }
            }
            res += Max;
            return res;
        };
    
        ll ans = 0;
    
        function<void(int, int)> dfs = [&](int u, int fa) {
            vector<pair<ll, int>> dp0;
            for (auto it : G[u]) {
                int v = it.fi, w = it.se;
                if (v != fa) {
                    dfs(v, u);
                    dp[u][1] += dp[v][0] + w;
                    dp0.push_back(MP(dp[v][0] + w, v));
                }
            }
            sort(dp0.rbegin(), dp0.rend());
            for (int i = 0; i < min(sz(dp0), k - 1); i++) {
                dp[u][0] += dp0[i].fi;
            }
            dp[u][1] = max(dp[u][1], calc(u, k - 2, fa));
            ans = max(ans, max(dp[u][1], calc(u, k - 1, fa)));
        };
    
        dfs(0, 0);
        cout << ans << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
        freopen("output.out", "w", stdout);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    H. Set1

    题意:
    同Set2类似,不过是每次删除最小的一个后再随机删除(k-1)个。如果个数小于(k)就不删除。然后问每个数剩下的概率。
    范围有点不同:(nleq 5000)

    思路:
    首先看范围就能明确这个题可以使用(O(n^2))的做法,一般就是dp。
    这个题可以类似于约瑟夫环的删除那样去思考,我们定义(dp[n][i])表示最后还有(n)个数,第(i)个最终没被删去的概率。那么接下来就开始删,首先第一个默认要被删去,然后会随机进行删除,假设左边删掉(t)个,那么(i)这个位置就会变到(i-t-1)这个位置。后面的是没影响的。据此我们可以写出(dp)转移式。

    [dp[i][j]=sum_{t=0}^{i-2}frac{{i-2choose t}cdot{n-ichoose k-t}}{n-1choose k}dp[i-k-1][j-t-1] ]

    初一看复杂度是(O(n^2k))的,但实际上对于第一维只有(O(frac{n}{k}))个状态有用。
    那么直接跑上述dp复杂度实际上是(O(n^2))的。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/05 16:45:03
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5000 + 5, MOD = 998244353;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
    int fac[N], inv[N];
    void init() {
        fac[0] = 1;
        for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
        inv[N - 1] = qpow(fac[N - 1], MOD - 2);
        for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    }
    
    int C(int n, int m) {
        return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    void run() {
        int n, k;
        cin >> n >> k;
        if (n <= k) {
            for (int i = 1; i <= n; i++) {
                cout << 1 << " 
    "[i == n];
            }
            return;
        }
        int r = n % (k + 1);
        if (r == 0) {
            for (int i = 1; i <= n; i++) {
                cout << 0 << " 
    "[i == n];
            }
            return;
        }
        vector<int> ans(n + 1);
        vector<vector<int>> dp(n + 1, vector<int>(n + 1));
        for (int i = 1; i <= r; i++) {
            dp[r][i] = 1;
        }
        vector<int> pre(n + 1);
        for (int i = k; i <= n; i++) {
            pre[i] = qpow(C(i, k), MOD - 2);
        }   
        for (int i = r + k + 1; i <= n; i += k + 1) {
            for (int j = 2; j <= i; j++) {
                int L = j - 2, R = i - j;
                for (int t = 0; t <= k; t++) {
                    if (t <= L && k - t <= R) {
                        dp[i][j] = (dp[i][j] + 1ll * C(L, t) * C(R, k - t) % MOD * pre[i - 1] % MOD
                         * dp[i - k - 1][j - t - 1] % MOD) % MOD;
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            cout << dp[n][i] << " 
    "[i == n];
        }
    }
    
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    I. Paperfolding

    显然我们可以将所有的折纸方案数归为只有两种的情况。
    并且每折一次,对应方向的折现都会翻倍。
    因为求的是期望,所以与顺序无关,我们可以直接枚举横向折多少次、竖向折多少次,然后直接根据期望定义统计答案即可。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/04 12:49:25
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5, MOD = 998244353;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if (b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    
    void run() {
        ll n;
        cin >> n;
        int res = 1ll * 2 * qpow(3, n) % MOD;
        res = (res + qpow(2, n)) % MOD;
        res = (res + qpow(4, n)) % MOD;
        res = 1ll * res * qpow(qpow(2, n), MOD - 2) % MOD;
        cout << res << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    L. Set1

    题意:
    给定一个(1)~(n)的集合,保证(n)为奇数。
    然后每次首先删除最小的一个数,之后再在剩下的数中随机删除一个数直到还剩下(1)个数。
    现在对于每个数(i),回答数(i)剩下的概率。

    思路:
    (p=frac{n}{2}),首先有观察:

    • 对于一个数(i),删除的最小的(p)个数一定在他左边,他右边的数一定是被随机删掉的。

    接下来考虑枚举所有情况,现在我们知道其右边有(n-i)个数,他们一定会和左边的(n-i)个一操作进行配对,然后剩下的两两进行配对。
    先考虑第一种,左右互相配对的方案数:也就是我们要从左边选出(n-i)个位置,然后还要乘以一个阶乘,即为({i-1choose n-i}cdot (n-i)!)
    第二种就是剩下(i-1-(n-i))个两两匹配,那么答案就是(sum_{j=0}{i-1-(n-i)-2jchoose 2})。注意最后还要除以一个阶乘,因为顺序是无关的。
    那么将两者乘起来就是答案。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/04 16:15:23
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5e6 + 5, MOD = 998244353;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
    int fac[N], inv[N];
    void init() {
        fac[0] = 1;
        for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
        inv[N - 1] = qpow(fac[N - 1], MOD - 2);
        for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    }
    
    int C(int n, int m) {
        return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    int cat(int n) {
        if (n == 0) return 1;
        return 1ll * C(2 * n, n) * qpow(n + 1, MOD - 2) % MOD;
    }
    
    int ans[N];
    
    void run() {
        int n;
        cin >> n;
        int k = n / 2;
        for (int i = 1; i <= k; i++) {
            ans[i] = 0;
        }
        for (int i = k + 1; i <= n; i++) {
            int p = i - 1 - (n - i);
            int res = 1ll * C(i - 1, n - i) % MOD * fac[n - i] % MOD;
            int res2 = 1ll * fac[p] * qpow(1ll * qpow(2, p / 2) * fac[p / 2] % MOD, MOD - 2) % MOD;
            res = 1ll * res * res2 % MOD;
            ans[i] = res;
        }
        int tot = 0;
        for (int i = 1; i <= n; i++) {
            tot += ans[i];
            if (tot >= MOD) tot -= MOD;
        }
        tot = qpow(tot, MOD - 2);
        for (int i = k; i <= n; i++) {
            ans[i] = 1ll * ans[i] * tot % MOD;
        }
        for (int i = 1; i <= n; i++) {
            cout << ans[i] << " 
    "[i == n];
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        init();
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    
  • 相关阅读:
    new Vue() 和 export default {}及Vue页面组件和标签组件说明与比较(非常重要)
    权限管理开源框架(非常重要)
    java 异常2
    java 异常
    java 内部类3(匿名内部类)
    java 内部类2(成员内部类)
    java 内部类1
    java 多态
    java 接口
    java abstract
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13463155.html
Copyright © 2011-2022 走看看