Educational Codeforces Round 125 (Rated for Div. 2)(D、E补题)

E. Star MST

题意:

给定\(N\)个点的完全无向图,你现在可以给边赋值的范围是\([1,k]\),问当前图与\(1\)相连的边的边权总和等于当前图的最小生成树的边权和的图有多少个?

思路:

由题意可得想要让与\(1\)连边的边权和等于最小生成树边权和,那么说明剩下\(n-1\)个点与\(1\)相连的点组成的就是最小生成树之一,那么这就说明\(W_{(1,u)}<=W_{(u,v)}\),所以可以考虑与\(1\)相连的边的边权,其他的边权很明显是要满足上述不等式,所以定义\(f(i,j)\)为有\(i\)个点与\(1\)直接相连,且边权\(≤j\),那么此时考虑边权又选中了\(k\)个点放入图中,且边权为\(j+1\),那么选点的方案数就是\({n-i-1\choose{k}}\),边的数量为\(\frac{k(k-1)}{2}+k×i\),剩余边的范围\([j+1,m]\),所以边的赋值范围数量\((m-j)^{\frac{k(k-1)}{2}+k×i}\)
那么转移方程就是\(f(i+k,j+1)=f(i+k,j+1)+f(i,j)×{n-i-1\choose{k}}×(m-j)^{\frac{k(k-1)}{2}+k×i}\)
最终答案就是\(f(n-1,m)\)

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 300;
const int mod = 998244353;
int dp[N][N];
int fact[N], infact[N];
int n, m;
int qmi(int a, int k) {
    int res = 1;
    while (k) {
        if (k & 1) res = res * a % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return res;
}
void init() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++) {
        fact[i] = i * fact[i - 1] % mod;
    }
    infact[N - 1] = qmi(fact[N - 1], mod - 2) % mod;
    for (int i = N - 2; i >= 1; i--) {
        infact[i] = infact[i + 1] * (i + 1) % mod;
    }
}
int C(int n, int m) {
    if (m > n) return 0;
    return fact[n] * infact[m] % mod * infact[n - m] % mod;
}
signed main() {
    init();
    cin >> n >> m;

    dp[0][0] = 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int k = 0; k + i < n; k++) {
                int temp = dp[i][j] * C(n - i - 1, k) % mod * qmi((m - j), k * (k - 1) / 2 + k * i) % mod;
                dp[i + k][j + 1] += temp;
                dp[i + k][j + 1] %= mod;
            }
        }
    }

    cout << dp[n - 1][m] << endl;
}

D. For Gamers. By Gamers.

题意:

现在有\(C\)元钱,给定\(n\)个小队的招募费用,血量和攻击力,有\(m\)只怪物需要打败,每次战斗你只可以选择一种队伍,选择多个,问你在花费不超过\(C\)且小队成员不死亡的情况的,打败怪物的最小花费是多少?
与怪物战斗不是回合制,而是每时每刻都在掉血,胜利就代表着怪物死亡的时间比人死的早

思路:

选择\(x\)个人与当前怪物战斗,胜利可以推导出,\(x\)个人的\(hp×ATK≥\)怪物的\(HP×ATK\),把这个\(hp×ATK\)称为能力值,所以可以定义\(dp(cost)\)为花费为\(cost\)的情况下的可以招募的\(x\)个人的最大能力值,最后每次查询的时候,二分查询能力值比怪物大的最小花费

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int n, C;
struct node {
    int cost;
    int damage;
    int hp;
} a[N];
int now[N];
int dp[N];
signed main() {
    cin >> n >> C;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].cost >> a[i].damage >> a[i].hp;
        now[a[i].cost] = max(a[i].damage * a[i].hp, now[a[i].cost]);
    }
    for (int i = 1; i < N; i++) {
        dp[i] = max(dp[i], dp[i - 1]);
        for (int j = i; j < N; j += i) {
            int num = j / i;
            dp[j] = max(dp[j], num * now[i]);
        }
    }
    int m;
    cin >> m;
    while (m--) {
        int D, H;
        cin >> D >> H;
        int t = upper_bound(dp + 1, dp + N + 1, D * H) - dp;
        if (t > C) {
            puts("-1");
        } else {
            cout << t << " ";
        }
    }
    return 0;
}
posted @ 2022-03-23 20:37  Wraith_G  阅读(28)  评论(0)    收藏  举报
// //