“蔚来杯“2022牛客暑期多校训练营(加赛)

本文介绍了'蔚来杯'多校训练营中的音游问题,涉及判定分数计算及复读策略优化。同时探讨了群组复读中冰红茶分配的最优化解。通过算法实现,展示了如何用树形dp和差分技巧解决这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

"蔚来杯"2022牛客暑期多校训练营(加赛)

[题目链接]("蔚来杯"2022牛客暑期多校训练营(加赛)_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com))

M Maimai DX 2077

题目大意

某个音游有四种音符,每种音符有五个判定。不同音符的不同判定会获得不同的基础分数。绝赞的判定会单独计算分数。给定一次游玩中,每种音符每种判定的数量,问达成度。

题解

见代码。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
double a[10][10] = {{1, 1, 0.8, 0.5, 0}, {2, 2, 1.6, 1.0, 0}, {3, 3, 2.4, 1.5, 0}, {5, 5, 2.5, 2, 0}};
double b[10] = {1, 0.5, 0.4, 0.3, 0};
double num[10][10];
double A, B, A0, B0;
int main()
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            cin >> num[i][j];
            A0 += num[i][j] * a[i][j];
            A += num[i][j] * a[i][0];
        }
    }
    for (int i = 0; i < 5; i++)
    {
        B0 += num[3][i] * b[i];
        B += num[3][i] * b[0];
    }
    cout << fixed << setprecision(9) << A0 / A * 100 + B0 / B << endl;
    return 0;
}

E Everyone is bot

题目大意

有 n 个人打算在群里复读。

一次复读的过程如下:每一轮,n 个人按照编号从小到大依次执行以下操作。

① 如果这个人在前几轮已经进行过复读,他不会再次复读。也就是说,每个人最多只会复读一次。

② 否则他可以选择是否进行复读。

如果某一轮没有人进行复读,那么复读的过程结束。

对于第 i 个人,如果他是所有人中第 j 个进行复读的,他会获得 a[i] [j] 瓶冰红茶。

但是如果他是所有进行了复读的人当中倒数第 p 个进行复读的人,那么他不会获得任何冰红茶,并且需要交出154 瓶冰红茶。

每个人都想最大化自己获得的冰红茶数量,求每个人会拿到多少冰红茶。

题解

思维题。复读人数是 n % p,且是前 n % p个人。

如果当前已经有 n − p 个人复读了,那么后面不会有任何人复读。因为一旦有人复读,剩下的人必然都会参与复读,那么这个人就会被禁言。所以谁都不会这么做。

同样,如果有 n − 2p 个人复读了,那么后面不会有任何人复读,因为一旦他复读了,接下来一定有 p − 1 个人加入复读。而这时候是 n − p 个人复读的状态,剩下 p 个人一定不会复读,那么他就被禁言了。

同样可以推出,如果当前复读人数是 n − kp 那么后面不会有人复读。

前 n mod p 个人必然一上来就复读。可以考虑如果有人不复读,后面本来没有机会的人必然会抓住机会,那么前面有人就会失去机会。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
int n, p;
int a[maxn][maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n % p; i++)
        cout << a[i][i] << " ";
    for (int i = n % p + 1; i <= n; i++)
        cout << 0 << " ";
    cout << endl;
    return 0;
}

H Here is an Easy Problem of Zero-chan

题目大意

有一棵 n 个节点,且以 1 为根的有根树,第 i 个点的点权为 i。多次查询编号为 x 的点,∏ lca(i, x) (1<=i<=n)的末尾有多少个零。

题解

树形 dp 。

父节点u和子节点v,与1-n所有节点的lca中,只有包括子节点的子树这一部分不同,与父节点的lca为u,与子节点的lca为v。

转移式 dp[v] = dp[u] + size[v] * (cnt[v]2|5 − cnt[u]2|5),其中 size[v]代表 v 的子树大小,cnt[v]2|5 代表节点 v 能分解出多少个 2 或 5。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, q;
int siz[maxn], cnt2[maxn], cnt5[maxn], dp2[maxn], dp5[maxn];
vector<int> g[maxn];
int predfs(int u, int fa)
{
    siz[u] = 1;
    for (auto v : g[u])
    {
        if (v == fa)
            continue;
        siz[u] += predfs(v, u);
    }
    return siz[u];
}
void dfs(int u, int fa)
{
    dp2[u] = dp2[fa] + siz[u] * (cnt2[u] - cnt2[fa]);
    dp5[u] = dp5[fa] + siz[u] * (cnt5[u] - cnt5[fa]);
    for (auto v : g[u])
    {
        if (v == fa)
            continue;
        dfs(v, u);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    for (int i = 2; i < maxn; i++)
    {
        if (i % 2 == 0)
            cnt2[i] = cnt2[i / 2] + 1;
        if (i % 5 == 0)
            cnt5[i] = cnt5[i / 5] + 1;
    }
    cin >> n >> q;
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    predfs(1, 0);
    dfs(1, 0);
    for (int i = 1; i <= q; i++)
    {
        int x;
        cin >> x;
        cout << min(dp2[x], dp5[x]) << endl;
    }
    return 0;
}

J Jellyfish and its dream

题目大意

给一个序列,值为 0 - 2。如果 (ai + 1) % 3 = a(i+1)%n,就可以将 ai 赋值为 a(i+1)%n

问有限次操作后是否能使所有元素均相等。

题解

差分,后文中的变化全部指差分数组。

一次操作可以将相邻的 (2, 1) 变成 (0, 0),(1, 1) 变成 (2, 0),(0, 1) 变成 (1, 0)。不难发现 0 没有意义。可以通过 (0, 1) 变成 (1, 0)这个操作来移动 1的位置。

只要 1 的数量不少于 2 的数量即可。

说实话还不太懂。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int t, n;
int a[maxn], cnt[5];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        memset(cnt, 0, sizeof cnt);
        cin >> n;
        for (int i = 0; i < n; i++)
            cin >> a[i];
        for (int i = 0; i < n; i++)
        {
            cnt[(a[(i + 1) % n] - a[i] + 3) % 3]++;
        }
        if (cnt[1] >= cnt[2])
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值