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;
    }
    
  • 相关阅读:
    onmousewheel
    Zepto 使用中的一些注意点(转)
    oninput onpropertychange 监听输入框值变化
    try catch
    center的用法
    [转]你的编程语言可以这样做吗?(map/reduce的js示范) (转)
    vue中 $event 的用法--获取当前父元素,子元素,兄弟元素
    chrome的vue插件——vue.js devtools的安装
    说明与比较:new Vue() 和 export default {}
    Vue反转字符串及join(),reverse()与 split()函数用法解析
  • 原文地址:https://www.cnblogs.com/limil/p/14032709.html
Copyright © 2011-2022 走看看