计蒜客 Benelux Algorithm Programming Contest 2019 签到题解

本文深入探讨了算法竞赛中的策略制定,包括如何通过调查观众偏好来安排比赛,以最大化观众满意度,以及在不同游戏情景下的最优解策略,如通过数学原理确定游戏胜负。

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

链接:to

A . Appeal to the Audience

您是即将举行的Bordfite Arena竞赛比赛的总监。您已经邀请了一堆球员,现在正在为淘汰赛设置比赛,这将确定获胜者。如您所知,BordfiteArena是一款奖励技能的游戏,很少涉及运气。这意味着无论何时有任意数量的玩家玩ordfite竞技场的游戏,最熟练的玩家将永远获胜!因此已经知道了比赛的获胜者,您对此有些担心,您将如何安抚观众?

您进行了简短的调查,以找出观众觉得有趣的地方。没有惊喜:当人们看到熟练的选手竞争时,人们会发现它最有趣。每当比赛进行时,观众从比赛中获得的快乐就是球员技能水平的总和。观众从比赛中获得的总幸福感是所有比赛中获得的幸福感的总和。这是非常有用的信息,因为您当然希望观众在比赛结束时尽可能的开心。

此外,您花了一些时间来问人们他们喜欢哪种淘汰赛形式。事实证明,与其使用普通的旧二叉树作为淘汰日程,他们更喜欢一棵看起来很奇怪的根树,因此您决定使用它。这意味着您要完成的最后一步是将玩家划分到给定树的叶子上,以便在整个锦标赛中最大程度地提高观众的满意度。

样例输入

5 3 
5 4 3 
0 
0 
1 
1

样例输出

17

求出每个叶节点一共要加多少次 从小到大排 再和给的数组从小到大 匹配求乘积的和
这里用dfs 每个节点保留最大的路径 其他都插入优先队列中

最后记得答案用long long保存

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

int n, w[N], k;
int h[N], e[N * 2], ne[N * 2], idx;
priority_queue<int,vector<int>,greater<int>> q;

void add(int a,int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

int dfs(int u)
{
    int maxv = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int son = e[i];
        int dep = dfs(son);
        if (dep > maxv) //该分支的最长路径比当前最大值大  
        {
            if (maxv != 0)//将当前的长度插入队列 更新最大长度
            {
                q.push(maxv);
            }
            maxv = dep; 
        }
        else if (dep <= maxv)	q.push(dep);否则将该分支的长度插入队列
    }
    return maxv + 1;
}

int main()
{
    memset(h, -1, sizeof h);
    cin >> n >> k;
    for (int i = 1; i <= k; i ++ ) scanf("%d", &w[i]);
    sort(w + 1, w + 1 + k);
    for (int i = 1; i < n; i ++ ) 
    {
        int p;
        cin >> p;
        add(p, i);
    }
    q.push(dfs(0) - 1);
    long long res = 0;//这里要记得开long long
    for (int i = 1; i <= k; i ++ )
    {
        int t = q.top();
        q.pop();
        res += 1ll * t * w[i];
    }
    cout << res << endl;
    return 0;
}

B.Breaking Branches

您的父母认为,整个星期天在奈梅亨附近的穆克海德(Mookerheide)附近散步会很“有趣”。

尽管您可以通过解决头脑中的编程问题来消磨时间,但您的兄弟姐妹却没有那么奢侈。片刻之后,您的妹妹爱丽丝(Alice)和您的哥哥鲍勃(Bob)感到自己无可救药。他们一起尝试找出是否可以通过游戏打发时间(这个问题后来被称为Bob和Alice Pastime Conundrum)。最后,他们提出了以下简单的游戏。

他们发现长度为n的单个分支将成为游戏的主要对象。或者,Alice和Bob选择一个分支并将其分成两部分,以使两个部分都具有整数长度。最后一个能够打破其中一个棋子的玩家获胜。爱丽丝开始了,因为她是两者中的年轻人。

当然,您已经想到了这个游戏。假设鲍勃发挥最佳,爱丽丝能否赢得比赛?如果是这样,她应该先采取什么行动?

样例输入

2

样例输出

Alice
1

把树枝都变为1需要切n - 1次
如果n是奇数 最后一刀必然是Bob切
反之亦然

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

int n, a[N];

int main()
{
    cin >> n;
    if (n & 1) puts("Bob");
    else 
    {
        puts("Alice");
        puts("1");
    }
    return 0;
}

E.Efficient Exchange

您最近在银行获得了一份新奇的货币工作。人们可以在这里付款,并以各种奇怪的货币存入或提取钱。在工作的第一天,您会帮助来自奈梅贾的客户,奈梅贾是一个微不足道的小国,因其巨大的硬币而闻名,其价值等于10的幂,即1、10、100、1000等。该客户希望相当大的一笔付款,您不希望携带所有这些硬币往返金库。

image_看图王.png

因此,您决定先思考。您和客户一样都有大量的尼吉米亚硬币储备(大多数尼吉米亚公民都非常强大)。现在,您要尽量减少在任一方向上交换的硬币总数,以准确支付客户必须支付的费用。

例如,如果客户要支付83个硬币,则有很多方法可以进行兑换。这是三种可能性:

选项1.客户支付8个价值10的硬币和3个价值1的硬币。这需要交换8 + 3 = 11个硬币。

选项2。客户支付了一个价值100的硬币,您返回了价值10的硬币和7个价值1的硬币。这需要交换1 +1 + 7 = 9个硬币。

选项3。客户支付一枚价值100的硬币和3枚价值1的硬币。您返回2枚价值10的硬币。这需要交换1 + 3 + 2 = 6枚硬币。

事实证明,这样做的最后一种方法需要最少的硬币。

样例输入

83

样例输出

6

(我做的很麻烦 自己都不知道怎么过的)本题用的dp状态机模型
f[i][0] 表示这一位都减去 所需要的硬币数
f[i][1] 表示这一位补足10 所需要的硬币数

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

string x;
vector<int> sum, sum1;
int f[N][2]; //0 减去 1 补足10
int book[20];

int main()
{
    for (int i = 0; i <= 9; i ++ ) book[i] = i;
    book[10] = 1;
    cin >> x;
    sum.push_back(0);
    for (int i = x.size() - 1; i >= 0; i -- ) sum.push_back(x[i] - '0');
    int n = x.size();
    for (int i = 1; i <= n; i ++ )
    {
        f[i][0] = min(
        f[i - 1][0] + book[sum[i]], // 前一位减去
         f[i - 1][1] + book[sum[i] + min(1, i - 1)]// 前一位补足 此位要+1
         // 如果是最开始则不加1 且 此位为10 应消耗一枚  及 sum[10] = 1 下同
         );

        f[i][1] = min(
        f[i - 1][0] + 10 - sum[i], 
        f[i - 1][1] + 10 - sum[i] - min(1, i - 1)
        );
    }
    cout << min(f[n][0], f[n][1] + 1) << endl;
    return 0;
}

J.Jazz it Up!

您与一些朋友一起组建了无调打击乐家和大提琴家乐队。你们在一起已经玩了几年了,但是您对当前的游戏水平感到不满意。在研究一些有趣的新样式时,您会被爵士世界的复杂细节所吸引。

image.png

当然,虽然您不能立即应用所学到的所有新事物,但您想从乐队演奏的音乐中即兴创作一些好的新节奏人物开始。您将在每个小节都有的节奏中弹奏ñn个拍子,然后将每个拍子分成米米笔记。总共,您将拥有纳米Ñ 米每栏的注释。

乐队里的每个人都知道爵士乐中没有广场的空间。因此,条形中的音符数应为无平方数。也就是说,没有数字k> 1ķ>1这样k ^ 2ķ
2
将条形中的音符数量除。

打击乐手已经建议每个小节拍数 ñn;现在由您来决定每个节拍有多少个音符,这些音符不会留出正方形的空间。

在第二个样本中 n = 30ñ=3 0和m = 7米=7。这行得通,因为2≤m <n2≤米<n和m \次n = 210米×ñ=2 1 0没有除数k ^ 2ķ
2
对于任何k> 1ķ>1。

样例输入

3

样例输出

2

思路很简单 但我写的很长 不知道是不是用麻烦了
将n分解质因数 得到质数p1 … pk 求答案为任意其他质数
这里用到 筛质数 和 并查集
先枚举每一个数 i 不是质数 那么让 p[i] = i + 1;
否则 p[i] = i;

分解质因数 每一个质数 p i p_i pi 让 p[ p i p_i pi] = p i p_i pi + 1;

答案就是p[2] 的祖宗节点 (1 0 不是质数)不用枚举

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

int n, primes[N], cnt, p[N];
bool st[N], judge[N];

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void get_prime(int x)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++] = i, judge[i] = true;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

int main()
{
    cin >> n;
    get_prime(n);//筛质数
    for (int i = 1; i <= n; i ++ )
    {
        if (judge[i]) p[i] = i;//如果次数
        else p[i] = i + 1;
    }
    p[1] = 2;
    for (int i = 2; i <= n / i; i ++ ) 
    {
        if (n % i == 0) 
        {
            p[i] = i + 1;
            n /= i;
        }
    }
    if (n > 1) p[n] = n + 1;
    cout << find(p[1]) << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值