• AtCoder Beginner Contest 163


    传送门

    A - Circle Pond

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    int main() {
        int n;
        scanf("%d", &n);
        printf("%.6f
    ", 2.0 * acos(-1) * n);
        return 0;
    }
    A.cpp

    B - Homework

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    int main() {
        int n, m;
        scanf("%d%d", &m, &n);
        for(int i = 0, x; i < n; i++) {
            scanf("%d", &x);
            m -= x;
        }
        printf("%d
    ", m < 0 ? -1 : m);
        return 0;
    }
    B.cpp

    C - management

    题意:给一棵N个节点的有根树,求每个节点的儿子数。

    数据范围:$ 2 leq N leq 2 imes 10^{5} $

    题解:由于输入直接给的是每个节点的父节点,直接计数即可。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 2e5 + 5;
    int a[N];
    int main() {
        int n;
        scanf("%d", &n);
        for(int i = 1, x; i < n; i++) {
            scanf("%d", &x);
            a[x]++;
        }
        for(int i = 1; i <= n; i++) {
            printf("%d
    ", a[i]);
        }
        return 0;
    }
    C.cpp

    D - Sum of Large Numbers

    题意:当前有N + 1个整数:10100,10100+1,...,10100+N,求取不少于K个数的和的可能值的数量(mod 1e9+7)。

    数据范围:$ 1 leq N leq 2 imes 10^{5},1 leq K leq N+1 $

    题解:10100很大,所以取K个数的总和不可能等于取K+1个数的总和,所以只需要枚举取多少个数。

    对于取K个数,可以求出取K个值的最小最大值,在这两个值之间的值都可以取到,个数就是最大值-最小值+1。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int MD = 1e9 + 7;
    void add(int& x, int y) {
        x += y;
        if(x >= MD) x -= MD;
        if(x < 0) x += MD;
    }
    int cal(int l, int r) {
        return 1LL * (l + r) * (r - l + 1) / 2 % MD;
    }
    int main() {
        int n, k, ans = 0;
        scanf("%d%d", &n, &k);
        for(int i = k; i <= n + 1; i++) {
            add(ans, cal(n + 1 - i, n) - cal(0, i - 1) + 1);
        }
        printf("%d
    ", ans);
        return 0;
    }
    D.cpp

     E - Active Infants

    题意:有N个小孩,第i个孩子的位置为i,活跃值为Ai,现在将N个小孩重新排列,每个小孩获得的开心值为Ai与重新排列前后位置差的乘积,求最大可能的开心值总和。

    数据范围:$ 2 leq N leq 2000, 1 leq A_{i} leq 10^{9} $

    题解:可以发现将A较大的值放在边上更优,以A降序,然后就是一个区间dp,枚举当前值放左边、右边进行更新。

    $ f[l][r] = max(f[l+1][r] + A_{now} imes left |  p_{now} - l ight |,f[l][r-1]+A_{now} imes left |  p_{now} - r ight | )$

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 2e3 + 5;
    ll f[N][N];
    pair<int, int> p[N];
    ll cal(int cnt, int l, int r) {
        if(l > r) return 0;
        if(~f[l][r]) return f[l][r];
        ll ans = 1LL * p[cnt].first * abs(p[cnt].second - l) + cal(cnt + 1, l + 1, r);
        ans = max(ans, 1LL * p[cnt].first * abs(p[cnt].second - r) + cal(cnt + 1, l, r - 1));
        return f[l][r] = ans;
    }
    int main() {
        int n;
        scanf("%d", &n);
        for(int i = 1, x; i <= n; i++) {
            scanf("%d", &x);
            p[i] = {x, i};
        }
        sort(p + 1, p + n + 1,[](pair<int, int> a, pair<int, int> b) {
            return a.first > b.first;
        });
        memset(f, -1, sizeof f);
        printf("%lld
    ", cal(1, 1, n));
        return 0;
    }
    E.cpp

     F - path pass i

    题意:给一棵N个节点的无根树,每个节点有一个颜色属性c,对于每个颜色,求经过这种颜色的简单路径的数量。

    数据范围:$ 1 leq c_{i} leq N leq 2 imes 10^{5} $

    题解:把问题转换成不经过这种颜色的简单路径的数量,总数f[N] = N*(N+1)/2减去它即可。

    其中不经过颜色i的简单路径的数量为:$ sum_{u!=v,u!=w,v!=w,c_{u}=c_{v}=i,forall w   epsilon  path(u,v), c_{w} != i} f[dis(u,v)-1] $。

    以任意一点为根节点,遍历的时候同时更新相应的值,具体看代码。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 2e5 + 5;
    vector<int> G[N];
    int C[N], num[N], sum[N];//num[i]代表i子树的节点数目,sum[i]代表以颜色为i的节点(其祖先没有颜色为i的节点)为根节点的子树大小总和
    ll ans[N];
    ll cal(int x) {
        return 1LL * x * (x + 1) / 2;
    }
    void dfs(int u, int fa) {
        int c = C[u], save = sum[c];
        num[u] = 1;
        for(auto v : G[u]) {
            if(v == fa) continue;
            int t = sum[c];
            dfs(v, u);
            int dt = sum[c] - t;
            ans[c] -= cal(num[v] - dt);//num[v]-dt代表相邻两个节点之间的节点数
            num[u] += num[v];
        }
        sum[c] = save + num[u];
    }
    int main() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &C[i]);
        }
        for(int i = 1, u, v; i < n; i++) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i = 1; i <= n; i++) {
            ans[i] = cal(n);
        }
        dfs(1, -1);
        for(int i = 1; i <= n; i++) {
            int t = n - sum[i]; //多出来的节点还要减掉
            ans[i] -= cal(t);
            printf("%lld
    ", ans[i]);
        }
        return 0;
    }
    F.cpp
  • 相关阅读:
    tomcat-jvm参数优化
    k8s集群命令用法
    Zabbix-配置QQ邮箱报警通知
    zabbix监控实现原理
    adb无线调试安卓
    tiddlywiki安装和入门
    python处理excel和word脚本笔记
    路由和交换机调试笔记
    linux常用命令
    进程和线程的代码实现
  • 原文地址:https://www.cnblogs.com/zdragon1104/p/12734682.html
Copyright © 2020-2023  润新知