zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 001 题解

    A-BBQ Easy (排序)

    题意

    题解

    排序后取奇数位置的数即可。

    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1e5;
    int arr[N];
    typedef long long ll;
    int main() {
        int n;
        cin >> n;
        for(int i = 1; i <= 2 * n; i++) {
            cin >> arr[i];
        }
        sort(arr + 1 , arr + 2 * n + 1);
        ll tot = 0;
        for(int i = 1; i <= 2 * n; i += 2) {
            tot += arr[i];
        }
        cout << tot << endl;
    }
    

    B-Mysterious Light (gcd)

    题意

    题解

    手动模拟一下发现就是一个求n-x和x的gcd的过程。

    ll solve(ll a, ll b) {
        if(!b) {
            return a;
        }
        ll res = 0;
        res += ((a - 1) / b) * 2 * b;
        res += solve(b, a % b);
        return res;
    }
     
    int main() {
        IOS;
        ll n, x;
        cin >> n >> x;
        cout << solve(n - x, x) + n << endl;
    }
    

    C-Shorten Diameter (树分治,暴力dfs)

    题意

    给你一颗无根树,要求删除最少结点使得剩余的图还是一颗树且直径不大于K。

    题解

    由于树直径的中点是唯一的,且每个点到这个点的距离不超过直径的一半(显然)。
    直径的中点可能在点上(直径为偶数)也可能在边上(直径为奇数)。一个暴力的做法是根据K的奇偶来枚举最终剩余的树的直径中点,删除距离该点超过K/2的所有点,取其中最小。复杂的$$O(n^2)$$
    由于本题数据范围小,可以暴力。若N非常大,要用到树分治。

    
    const int N = 3e5 + 10;
    const double eps = 1e-5;
     
    vector<int> np[N];
    typedef pair<int, int> PII;
     
     
    int n, k;
    int dfs(int p, int fa, int dep) {
        int res = 0;
        if(dep > k / 2) res++;
        for(int nt : np[p]) {
            if(nt == fa) continue;
            res += dfs(nt, p, dep + 1);
        }
        return res;
    }
     
    int main() {
        IOS;
        cin >> n >> k;
        
        for(int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            np[u].push_back(v);
            np[v].push_back(u);
        }
        int ans = n - 1;
        if(k % 2 == 0) {
            for(int i = 1; i <= n; i++) { //枚举点
                int tot = 0;
                ans = min(ans, dfs(i, 0, 0));
            }
        } else {
            for(int i = 1; i <= n; i++) { //枚举边,直径中心为边的中心
                int tmp = 0;
                for(int j : np[i]) {
                    ans = min(ans, dfs(i, j, 0) + dfs(j, i, 0));
                }
            }
        }
        cout << ans << endl;
    }
    

    D-Arrays and Palindrome (思维)

    题意

    题目比较绕,详见洛谷的翻译

    题解

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen(".//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e5 + 10;
    const double eps = 1e-5;
    
    int arr[N];
    
    int main() {
        IOS;
        int n, m;
        cin >> n >> m;
        int cnt = 0;
        int odd1 = 0, odd2 = 0;
        for(int i = 1; i <= m; i++) {
            cin >> arr[i];
            if(arr[i] % 2) {
                cnt++;
                if(cnt == 1) odd1 = i;
                if(cnt == 2) odd2 = i;
            }
        }
        if(m == 1) {
            cout << arr[1] << endl;
            if(arr[1] == 1) {
                cout << 1 << endl;
                cout << 1 << endl;
            } else {
                cout << 2 << endl;
                cout << 1 << " " << arr[1] - 1 << endl;
            }
        }
        else if(cnt > 2) cout << "Impossible" << endl;
        else {
            if(cnt == 2) {
                swap(arr[odd1], arr[1]);
                swap(arr[odd2], arr[m]);
            } else if(cnt == 1) {
                swap(arr[odd1], arr[1]);
            }
            for(int i = 1; i <= m; i++) cout << arr[i] << " 
    "[i == m];
            if(arr[m] - 1) cout << m << endl;
            else cout << m - 1 << endl;
            cout << arr[1] + 1 << " ";
            for(int i = 2; i < m; i++) {
                cout << arr[i] << " ";
            }
            if(arr[m] - 1) cout << arr[m] - 1 << endl;
            else cout << endl;
        }    
    }
    

    E-BBQ Hard (dp)

    题意

    中文题意

    题解

    组合数(left( egin{matrix} x+y \ x end{matrix} ight))几何意义是从((0, 0))((x, y))的路径数。

    略证:

    (left( egin{matrix} x+y \ x end{matrix} ight) = left( egin{matrix} x+(y-1) \ x end{matrix} ight)+left( egin{matrix} (x-1)+y \ x-1 end{matrix} ight))

    故题目可转换为从((0, 0))((a_i+a_j, b_i+b_j))的路径数,进一步可转化为((-a_i, -b_i))((a_j, b_j))。令每个((-a_i, -b_i))为1,然后dp。最后答案为每个((a_i, b_i))的和。还要减去每个((-a_i, -b_i))((a_i, b_i))的值,即(left( egin{matrix} 2(a_i+b_i) \ a_i+b_i end{matrix} ight)),然后除以2,因为题目要求的是(i<j)的数对。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen(".//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 2e3 + 10;
    const int M = 1e9 + 7;
    const double eps = 1e-5;
    
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    
    ll inv(ll x) {
        return qpow(x, M - 2, M);
    }
    
    ll f[N << 2], rf[N << 2];
    ll dp[N << 1][N << 1];
    
    ll C(int n, int m) {
        return f[n] * rf[n - m] % M * rf[m] % M;
    }
    typedef pair<int, int> PII;
    PII arr[300000];
    
    int main() {
        IOS;
        f[0] = rf[0] = 1;
        for(int i = 1; i < (N << 2); i++) {
            f[i] = (f[i - 1] * i) % M;
            rf[i] = (rf[i - 1] * inv(i)) % M;
        }
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++) {
            int a, b;
            cin >> a >> b;
            arr[i] = mp(a, b);
            dp[N - a][N - b]++;
        }    
        for(int i = 1; i < (N << 1); i++) {
            for(int j = 1; j < (N << 1); j++) {
                dp[i][j] = (dp[i][j] + (dp[i - 1][j] + dp[i][j - 1]) % M) % M;
            }
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++) {
            int a = arr[i].first, b = arr[i].second;
            ans += dp[N + a][N + b];
            ans %= M;
            ans -= C(2 * a + 2 * b, 2 * a);
            ans = (ans % M + M) % M;
        }
        ans = ans * 500000004 % M;
        cout << ans << endl;
    }
    

    F-Wide Swap (线段树,拓扑排序)

    题意

    中文题意

    题解

    (P_i)为下标,i为值构造新序列(即逆序列),题目变为若相邻的数相差大于K则可交换,求最小字典序。这个转换一下子把题目变得顺眼起来。
    为了字典序最小,小的值要越前越好。因此从1开始,如果合法(前面的数比自己大K)就不停向前移动,直到移不动为止。那么当前1和它前面的数(设为x)相对位置就固定不动了,而且这个位置关系是最优的,然后x向1连边,代表x在1之前,然后更新1的值(P_1)为INF。以此类推,建出的图优先队列拓扑排序一下即可。
    注意最后的序列还要在逆一次变回原序列对应的答案。

    复杂的(O(n^2)),但网上正解复杂为(O(n))。以后有时间再补。

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    const int N = 5e5 + 10;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    
    int mi[N << 2];
    int pe[N], rpe[N];
    int n;
    int deg[N];
    vector<int> np[N];
    
    void build(int l, int r, int rt) {
        if(l == r) {
            mi[rt] = rpe[l];
            return ;
        }
        mi[rt] = INF;
        int mid = (l + r) / 2;
        build(l, mid, rt << 1);
        build(mid + 1, r, rt << 1 | 1);
        mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
    }
    
    int query(int l, int r, int  L, int  R, int  rt) {
        if(l >= L && r <= R) {
            return mi[rt];
        }
        int mid =(l + r) / 2;
        int res = INF;
        if(L <= mid) res = min(res, query(l, mid, L, R, rt << 1));
        if(R > mid) res = min(res, query(mid + 1, r, L, R, rt << 1 | 1));
        mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
        return res;
    }
    
    void update(int l, int r, int p, int val, int rt) {
        if(l == r) {
            mi[rt] = val;
            return ;
        }
        int mid = (l + r) / 2;
        if(p <= mid) update(l, mid, p, val, rt << 1);
        else update(mid + 1, r, p, val , rt << 1 | 1);
        mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
    }
    
    int find(int p, int v, int k) {
        int l = 1, r = p - 1;
        while(l <= r) {
            int mid = (l + r) / 2;
            int tar = query(1, n, mid, p - 1, 1);
            if(tar >= v + k) {
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        l--;
        return l;
    }
    
    vector<int> ans;
    priority_queue<int, vector<int>, greater<int> > q;
    
    int main() {
        int k;
        cin >> n >> k;
        for(int i = 1; i <= n; i++) {
            cin >> pe[i];
            rpe[pe[i]] = i;
        }
        build(1, n, 1);
        for(int i = 1; i <= n; i++) {
            int p = find(pe[i], i, k);
            if(p) {
                np[rpe[p]].push_back(i);
                deg[i]++;
            }
            update(1, n, pe[i], INF, 1);
        }
        
        for(int i = 1; i <= n; i++) {
            if(!deg[i]) {
                q.push(i);
            }
        }
        while(!q.empty()) {
            int cur = q.top();
            q.pop();
            ans.push_back(cur);
            for(int nt : np[cur]) {
                deg[nt]--;
                if(!deg[nt]) q.push(nt);
            }
        }
        for(int i = 0; i < ans.size(); i++) {
            pe[ans[i]] = i + 1;
        }
        for(int i = 1; i <= n; i++) cout << pe[i] << endl;
    }
    
  • 相关阅读:
    973. K Closest Points to Origin
    919. Complete Binary Tree Inserter
    993. Cousins in Binary Tree
    20. Valid Parentheses
    141. Linked List Cycle
    912. Sort an Array
    各种排序方法总结
    509. Fibonacci Number
    374. Guess Number Higher or Lower
    238. Product of Array Except Self java solutions
  • 原文地址:https://www.cnblogs.com/limil/p/14032709.html
Copyright © 2011-2022 走看看