• Codeforces Round #703 (Div. 2) A、B、D、E题解


    写在前边

    链接:Codeforces Round #703 (Div. 2)
    这次的交互题是真不会做。

    A. Shifting Stacks

    链接:A题链接

    题目大意:

    (n)摞高度分别为(h_i)的山,现在我们可以从每次从第(i)座山移动高度为(1)的移到(i + 1)座山上,问是否可以形成一个严格单调递增的山脉。

    思路

    贪心的想我们一直挪山,让第一座山高度为(0),第二座山高度为(1),第三座山高度为为(2),依次类推就可以了,这样形成(1,2,3,...,i)座山的总需要的高度就是(need = cfrac{i(i-1)}{2}), 所以我们对于枚举到的每一座山只需要判断目前拥有的高度(sumlimits_{k = 1}^i h[k])是否能构造出(need)即可,即(sumlimits_{k = 1}^i h[k] > cfrac{i(i-1)}{2})

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    const int N = 110;
    LL h[N];
    
    void solve() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) scanf("%lld", &h[i]);
        LL sum = 0, need = 0;
        for (int i = 0; i < n; i++) {
            need += i;
            sum += h[i];
            if (sum < need) {
                puts("NO");
                return;
            }
        }
        puts("YES");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    B. Eastern Exhibition

    链接:B题链接

    题目大意:

    给定一堆((x,y)),两点距离定义为(|x_2 - x_1| + |x_2 - x_1|),现在需要选取有多少个点到每个点之和最小。

    思路

    首先想到(|x_2 - x_1|)(|x_2 - x_1|)坐标的距离互不影响,于是就可以转化成先求一维,然后利用乘法原理相乘就是结果。
    对于一维,就是经典的货仓选址了,排个序,对于奇数个点,那么就中位数唯一,如果是偶数,那么可以选择两个中位数以及之间任意位置即可,即([cfrac{n}{2}, cfrac{n}{2} + 1])

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    const int N = 1010;
    int x[N], y[N];
    
    void solve() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &x[i], &y[i]);
        }
        sort(x + 1, x + n + 1);
        sort(y + 1, y + n + 1);
        if (n & 1) puts("1");
        else {
            int calx = x[n / 2 + 1] - x[n / 2] + 1, caly = y[n / 2 + 1] - y[n / 2] + 1;
            printf("%lld
    ", (LL) calx * caly);
        }
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    D. Max Median

    链接:D题链接

    题目大意:

    给定一个数组长度为(n)的数组(a),求长度为至少(k)的子数组的最大中位数。

    思路

    参考博客:随处可见的阿宅
    枚举一个最大的中位数明显可以用二分来优化,然后再检查其合理性,二分枚举一个(x),检查其合理性即检查它是否为中位数的时候可以有一个技巧,即构造一个序列,让(geq x)的数
    (1),让(leq x)的数为(-1),那么这样来说,如果某一长度至少为(k)子段和大于(0),那么(x)就是这个子段的中位数,很神奇,那么这里可以用前缀和优化,剩下的就是枚举长度至少为(k)的前缀和了,所以剩下的任务就是找一个(i geq k)以及(j in [1, i - k]),且满足(s[i] - s[j] > 0),而对于(s[j])我们仅需要维护那个最小的前缀即可。

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    const int N = 2e5 + 10;
    int a[N], b[N], minpref[N]; 
    int n, k;
    
    bool check(int x) {
        for (int i = 1; i <= n; i++) b[i] = (a[i] >= x ? 1 : -1);
        for (int i = 1; i <= n; i++) b[i] += b[i - 1];
        for (int i = 1; i <= n; i++) minpref[i] = min(minpref[i - 1], b[i]);
        for (int i = k; i <= n; i++) {
            if (b[i] - minpref[i - k] > 0) return true;
        }
        return false;
    }
    
    void solve() {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
        int l = 1, r = n + 1;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        
        printf("%d
    ", l);
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        solve();
    
        return 0;
    }
    

    E - Paired Payment

    链接:E题链接

    题目大意:

    最短路问题,只不过是一次只能走两步,不能一次一步走,比如a->b->c,那么就是a->c,花费是((w_{ab} + w_{bc})^2)

    思路

    参考博客:随处可见的阿宅
    两天了,终于悟了,其实暴力跑单源最短路就可以,比如从(a->b->c) ((a, b, c)指点集,不是具体的点),那么就是从(a)搜到最短的(b),然后再从(b)搜到最短的(c),就是两重循环,然后看大佬一个很重要的优化就是,当(b)作为中间点的时候,我们可以维护一个(a->b)的最短路径,这样由于边权最大就是(50),所以最坏情况下更新次数也不会超过(50)的,那么这题就终于这么过了。

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <queue>
    
    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3,"Ofast","inline")
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int Mod = 10000007;
    
    const int N = 1E5 + 10, M = 4 * N;
    int h[N], e[M], ne[M], w[M], idx;
    int dist[N], mindist[N];
    bool st[N];
    
    void add(int a, int b, int c) {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    void Dijkstra() {
        priority_queue<PII, vector<PII>, greater<PII> > heap;
        heap.push({0, 1});
        memset(dist, 0x3f, sizeof dist), memset(mindist, 0x3f, sizeof mindist);
        dist[1] = 0;
    
        while (heap.size()) {
            auto t = heap.top();
            heap.pop();
            int var = t.second, cost = t.first;
            
            if (st[var]) continue;
            st[var] = true;
    
            for (int i = h[var]; i != -1; i = ne[i]) {
                int var1 = e[i], cost1 = w[i];
                if (mindist[var1] > cost1) {
                    for (int j = h[var1]; j != -1; j = ne[j]) {
                        int var2 = e[j], cost2 = w[j];
                        if (dist[var2] > (cost2 + cost1) * (cost2 + cost1) + cost) {
                            dist[var2] = (cost2 + cost1) * (cost2 + cost1) + cost;
                            heap.push({dist[var2], var2});
                        }
                    }
                    mindist[var1] = cost1;
                }
            }
        }
    }
    
    void solve() {
        int n, m;
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        for (int i = 1; i <= m; i++) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c), add(b, a, c);
        }
    
        Dijkstra();
    
        for (int i = 1; i <= n; i++) {
            if (dist[i] == 0x3f3f3f3f) printf("%d ", -1);
            else printf("%d ", dist[i]);
        }
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        solve();
        return 0;
    }
    
  • 相关阅读:
    二叉树进阶之寻找一棵二叉树中的最大二叉搜索子树
    二叉树进阶之求一棵二叉树中结点间最大距离
    软件工程各阶段的UML图
    软件工程各阶段的开发文档
    二叉树应用进阶之折纸(二叉树的右根左遍历)
    二叉树进阶应用之查找结点的后继结点
    二叉树进阶之满二叉树和完全二叉树
    二叉树进阶之搜索二叉树的判断与找出搜索二叉树中出错的结点
    二叉树进阶之平衡二叉树的判断
    二叉树基础之序列化和反序列化二叉树
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14457039.html
Copyright © 2020-2023  润新知