• [CodeForces]Codeforces Round #428 (Div. 2)


    A. Arya and Bran

    题意

    已知$n$天中一个人每天获得$a_i$块糖,但最多只能拿其中8块,多余的可以以后拿。判断最早哪一天能拿到$k$块。

    题解

    模拟每天的情况即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    inline int read() {
        int s = 1, x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return s * x;
    }
    
    int main() {
        int n = read(), k = read(), rst = 0; 
        for (int i = 1; i <= n; i++) {
            int ai = read();
            int dec = min(ai + rst, 8);
            rst += (ai - dec);
            k -= dec;
            if (k <= 0) return 0 * printf("%d\n", i);
        }
        return 0 * printf("-1\n");
    }
    

    B. Game of the Rows

    题意

    已知飞机上有$n$座位,每排编号1~8号座位,其中1和2、3和4、4和5、5和6、7和8相邻;另有$k$队士兵,每队$a_i$人,规定不同部队的士兵不能坐相邻座位。判断飞机能否载走所有士兵。

    题解

    贪心。首先考虑大于等于3人队,优先把他们往3456位或12、78位上塞;再考虑两人队,优先塞到12、78位,塞不下则看成三人队塞到3456位,还塞不下则看成两个一人队;最后考虑一人队即可。

    代码

    #include <bits/stdc++.h>
    
    inline int read() {
        int s = 1, x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return s * x;
    }
    
    int main() {
        int n = read(), k = read();
        int cnt[5] = {0, 0, 0, 0, 0};
        int rst[5] = {0, 0, 2 * n, 0, n};
        for (int i = 1; i <= k; i++) {
            int a = read();
            while (a >= 3) {
                if (rst[4] > 0) a -= 4, rst[4]--;
                else
                    if (rst[2] > 0) a -= 2, rst[2]--;
                    else return 0 * printf("NO\n");
            }
            cnt[a]++;
        }
        while (cnt[2] > 0) {
            if (rst[2] > 0) cnt[2]--, rst[2]--;
            else 
                if (rst[4] > 0) cnt[2]--, rst[4]--, rst[1]++;
                else cnt[2]--, cnt[1] += 2;
        }
        if (cnt[1] > rst[1] + rst[2] + rst[4] * 2) return 0 * printf("NO\n");
        return 0 * printf("YES\n");
    }
    

    C. Journey

    题意

    已知一棵树,求从编号为1的根节点到达叶子节点距离的期望。

    题解

    直接遍历这棵树,记录每个节点的深度和到达它的概率,每到一个叶子结点累加它的深度$\times$概率即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5+9;
    
    double res = 0.0;
    bool vis[N];
    vector<int> g[N];
    
    inline int read() {
        int s = 1, x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return s * x;
    }
    
    void dfs(int u, double d, double x) {
        queue<int> q; double y = 0.0;
        for (int v: g[u]) if (!vis[v]) q.push(v), y++;
        if (q.empty()) res += d * x;
        else {
            while (!q.empty()) {
                int v = q.front(); q.pop();
                vis[v] = 1;
                dfs(v, d + 1, x / y);
            }
        }
    }
    
    int main() {
        int n = read();
        for (int i = 1; i < n; i++) {
            int u = read(), v = read();
            g[u].push_back(v); g[v].push_back(u);
        }
        memset(vis, 0, sizeof(vis)); vis[1] = 1;
        dfs(1, 0, 1);
        return 0 * printf("%.8lf\n", res);
    }
    

    D. Winter is here

    题意

    已知$n$个数$a_1,a_2,...,a_n$,对于任意$k$个数的子集,若$i_1$ $<$ $i_2<...<$$i_k且gcd(a_{i_1},a_{i_2},...,a_{i_k})>1$,则这个子集的“力量”为$k\times gcd(a_{i_1},a_{i_2},...,a_{i_k})$。求所有子集的“力量”之和。

    题解

    直接考虑子集的最大公约数是多少然后统计时间复杂度显然很高,我们考虑一个数$i$整除子集中的所有数,那$i$一定整除子集的最大公约数,于是我们先统计能被$i$整除的子集个数。
    假设$n$个数中能被$i$整除的个数为$x$,则能被$i$整除的子集个数$b_i=\sum_{k=0}^x k\times {\binom{x}{k}}=x\times \sum_{k=0}^{x-1} {\binom{x-1}{k}}=x\times {2^{x-1}}$,再根据$b_i$倒过来使用容斥原理求和即可。

    代码

    #include <bits/stdc++.h>
    typedef long long ll;
    const ll N = 1e6+9, Q = 1e9+7;
    
    ll res, a[N], b[N], p[N];
    
    inline ll read() {
        ll s = 1, x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return s * x;
    }
    
    int main() {
        ll n = read();
        for (ll i = 0; i < n; i++) {ll x = read(); a[x]++;}
        memset(p, 0, sizeof(p)), p[0] = 1;
        for (ll i = 1; i <= n; i++) p[i] = 2 * p[i - 1] % Q;
        for (ll i = N - 1; i > 1; i--) {
            ll x = 0;
            for (ll j = i; j < N; j += i) x += a[j];
            if (x >= 0) {
                b[i] = x * p[x - 1] % Q;
                for (ll j = i * 2; j < N; j += i) b[i] = (b[i] - b[j] + Q) % Q;
                res += b[i] * i; res %= Q;
            }
        }
        return 0 * printf("%lld\n", res);;
    }
    

    E. Mother of Dragons

    题意

    已知$n$个顶点的图和k,要求将$k$分配给各个顶点(可以为$0$),当两个顶点有边直接相连时将产生它们乘积的价值,求一个分配方案使得产生的乘积之和最大。

    题解

    最优解一定是将$k$平均分配给图中的一个最大团。简单证明如下:
    首先对于两个顶点,由均值不等式,平均分配时产生的乘积最大,由此容易证到:对于团也是平均分配时的乘积和最大。
    假设将$k$分配给一个顶点个数为$c$的团,则产生的乘积之和为$s=(\frac{k}{c})^{2}\times \frac{c(c-1)}{2}=\frac{k^2(c-1)}{2c}$。
    现在有一个不属于该团的顶点$P$,它与团中顶点最多有$c-1$条边,则平均分配这$c+1$个顶点产生的乘积之和最大为$s'=(\frac{k}{c+1}){2}\times(\frac{c(c-1)}{2}+(c-1))=\frac{k2(c+2)(c-1)}{2(c+1)^2}$。
    简单做差,可以推到$s>s'$。
    即:$(1)$对于一个团,不要额外添加不属于它的顶点。
    假设除了这个顶点个数为$c$的团之外,还有$m$个顶点数最多为$c$的团,则产生的乘积之和为$s''=\sum_{i=1}m(\frac{k}{\sum_{i=1}{m}c_i})^{2}\times \frac{c(c-1)}{2}=(\frac{k}{\sum_{i=1}{m}c_i}){2}\times \sum_{i=1}^m\frac{c_i(c_i-1)}{2}\leq (\frac{k}{\sum_{i=1}{m}c_i}){2}\times \frac{c(c-1)}{2}$。
    简单做差,可以推到$s\geq s''$。
    即:$(2)$对于多个团,只要选其中的一个最大团。
    根据$(1)(2)$得证。
    最后找最大团可以通过$BronKerbosch$算法或者$dp$或者启发式搜索即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    const int N = 40, C = 20;
    
    int n, k, dp[1 << C];
    ll adj[N];
    
    inline int read() {
        int s = 1, x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') {if (ch == '-') s = -1; ch = getchar();}
        while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return s * x;
    }
    
    int maxc(){
        for (int i = 0; i < n; i++) {
            for (int j = 0, x; j < n; j++) {
                x = read(), adj[i] |= (ll) (x || i == j) << j;
            }
        }
        for (int i = 1; i < (1 << max(0, n - C)); i++) {
            int x = i;
            for (int j = 0; j < C; j++) {
                if ((i >> j) & 1) x &= adj[j + C] >> C;
            }
            if (x == i) dp[i] = __builtin_popcount(i);
        }
        for (int i = 1; i < (1 << max(0, n - C)); i++) {
            for (int j = 0; j < C; j++) {
                if ((i >> j) & 1) dp[i] = max(dp[i], dp[i ^ (1 << j)]);
            }
        }
        int ret = 0;
        for (int i = 0; i < (1 << min(C, n)); i++) {
            int x = i, y = (1 << max(0, n - C)) - 1;
            for (int j = 0; j < min(C, n); j++) {
                if ((i >> j) & 1) x &= adj[j] & ((1 << C) - 1), y &= adj[j] >> C;
            }
            if (x != i) continue;
            ret = max(ret, __builtin_popcount(i) + dp[y]);
        }
        return ret;
    }
    
    int main() {
        n = read(), k = read();
        int c = maxc();
        ld x = (ld) k / c;
        return 0 * printf("%.8Lf\n", x * x * c * (c - 1) / 2);
    }
    
  • 相关阅读:
    Linux异步IO
    基本数据类型总结--
    总结
    字典魔法二
    字典及其魔法
    元祖的魔法
    列表的特点
    运算符
    while ……else……和while……continue……和 while…………break…………
    作业---写一个程序,用户名 、密码输入错误3次 错误
  • 原文地址:https://www.cnblogs.com/jstztzy/p/7373889.html
Copyright © 2020-2023  润新知