【牛客小白月赛69】题解与分析A-F【蛋挞】【玩具】【开题顺序】【旅游】【等腰三角形(easy)】【等腰三角形(hard)】

比赛传送门:https://ac.nowcoder.com/acm/contest/52441

感觉整体难度有点偏大。

? 作者:Eriktse
? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?
? 个人博客:www.eriktse.com

A-蛋挞

签到题。

只需比较a / ba % b的大小即可。注意开longlong。

#include <bits/stdc++.h>
#define int long long
using namespace std;

signed main()
{
    int a, b;scanf("%lld %lld", &a, &b);
    if(a / b < a % b)printf("niuniu eats more than others");
    else if(a / b > a % b)printf("niuniu eats less than others");
    else printf("same");
    return 0;
}

B-玩具

排序贪心。

因为我们要将n个玩具全部买下,所以我们免单的玩具价格越高越好,我们将整个数组排升序后从后往前两个两个拿,且只付更高价格的玩具的钱

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 1e6 + 9;
int a[maxn];
signed main()
{
    int n;scanf("%lld", &n);
    for(int i = 1;i <= n; ++ i)scanf("%lld", a + i);
    sort(a + 1,a + 1 + n);
    
    int ans = 0;
    for(int i = n;i >= 1; -- i)
    {
        ans += a[i];
        i --;
    }
    printf("%lld\n", ans);
    return 0;
}

C-开题顺序

dfs。

题目数量比较小,我们可以枚举出所有的开题顺序,然后计算出最终分数取大即可,注意剪枝,当时间超过t的时候可以直接结束,此时的分数已经无效了。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 15;
int a[maxn], b[maxn], c[maxn], x[maxn], y[maxn];
int n, t, p;

bitset<maxn> vis;

//当前正在选第dep道题
int dfs(int dep, int ti, int sc)
{
    if(ti > t)return 0;//当累计做题时间已经超过了t说明比较已经结束了
    if(dep == n + 1)return sc;
    
    int res = sc;
    
    for(int i = 1;i <= n; ++ i)
    {
        if(vis[i])continue;
        //切了第i道题
        ti += x[i];
        vis[i] = true;
        res = max(res, dfs(dep + 1, ti, sc + max(c[i], a[i] - ti * b[i] - y[i] * p))); 
        vis[i] = false;
        ti -= x[i];
    }
    return res;
}

signed main()
{
    scanf("%lld %lld %lld", &n, &t, &p);
    for(int i = 1;i <= n; ++ i)
        scanf("%lld %lld %lld %lld %lld", a + i, b + i, c + i, x + i, y + i);

    printf("%lld\n", dfs(1, 0, 0));
    return 0;
}

D-旅游

最小生成树(并查集) + 二分。

首先我们知道要使得所有点互联,且边权尽可能小,应该建立一棵最小生成树,然后修复树中所有的边即可。

然后国家帮忙修复边权<=p的部分,那么我们可以想到,当p较大时,牛牛的资金肯定可以足够修复剩下的,当p较小时,牛牛要修的路就比较多,就修不了。

所以“y=牛牛能否修复剩下的路”是随着p单调的,当p大时,y=1,当p小时,y=0,我们要做的就是找到那个交界处,二分即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 9;

map<int, int> mp[maxn];

struct Edge
{
    int x, y, w;
};

int pre[maxn];
//路径压缩的并查集
int root(int x){return pre[x] = (pre[x] == x ? x : root(pre[x]));}

int a[maxn];//a里面存放最小生成树的所有边权
int n, m, c, cnt;

bool check(int k)
{
    int res = 0;//贪心求最小代价,数组逆序点乘
    for(int i = cnt, j = 0;i >= 1; -- i)
    {
        if(a[i] <= k)break;//<=k的部分国家买单不用考虑了
        res += (++ j) * a[i];
    }
    return res <= c;
}

signed main()
{
    scanf("%lld %lld %lld", &n, &m, &c);
    /*最小生成树,共3步*/
    vector<Edge> vec;
    //1.存边
    for(int i = 1;i <= m; ++ i)
    {
        int x, y, w;scanf("%lld %lld %lld", &x, &y, &w);
        vec.push_back({x, y, w});//将边存入vec中
    }
    //2.将边升序
    sort(vec.begin(), vec.end(), [](const Edge &u, const Edge &v)
         {
             return u.w < v.w;
         });
    //3.贪心建树,并查集判断连通性
    for(int i = 1;i <= n; ++ i)pre[i] = i;//并查集初始化
    for(auto &i : vec)
    {
        int x = i.x, y = i.y, w = i.w;
        if(root(x) == root(y))continue;
        a[++ cnt] = w;//a自然是升序的
        pre[root(x)] = root(y);
    }
    
    /*生成树结束*/
    
    //以下为二分部分
    int l = -1, r = 2e9;
    
    while(l + 1 != r)
    {
        int mid = (l + r) >> 1;
        if(check(mid))r = mid;
        else l = mid;
    }
    printf("%lld\n", r);
    return 0;
}

E-等腰三角形(easy)

暴力枚举。

枚举出所有三个点组成的三元组,注意不要重复。

可以通过海伦公式来求面积判断是否共线。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 500;
const double eps = 1e-6;

struct Point
{
    int x, y;
}p[maxn];

int dist(const Point &u, const Point &v)
{
    int dx = u.x - v.x;
    int dy = u.y - v.y;
    return dx * dx + dy * dy;
}

double area(double a, double b, double c)
{
    double p = (a + b + c) / 2.0;
    return sqrt(p * (p - a) * (p - b) * (p - c));
}

signed main()
{
    int n;scanf("%lld", &n);
    for(int i = 1;i <= n; ++ i)
        scanf("%lld %lld", &p[i].x, &p[i].y);
    int ans = 0;
    for(int i = 1;i <= n; ++ i)
    {
        for(int j = i + 1;j <= n; ++ j)
        {
            for(int k = j + 1;k <= n; ++ k)
            {
                int d1 = dist(p[i], p[j]);
                int d2 = dist(p[i], p[k]);
                int d3 = dist(p[j], p[k]);
                if(area(sqrt(d1), sqrt(d2), sqrt(d3)) <= eps)continue;
                if(d1 == d2 || d1 == d3 || d2 == d3)ans ++;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}

F-等腰三角形(hard)

这题肯定不能暴力枚举了。

我们可以发现,以整数点作为定点肯定无法构成等边三角形。

假如我们要构成一个等边三角形,那么就需要有60度的角,假如这个60度的角由两个角x,y相加而成,就有:

\[tan60\degree = tan(x+y)= \frac{tanx + tany}{1-tanx \times tany}
\]

其中tan60是一个无理数,但是后面的tanx, tany都是有理数,一个无理数无法通过有理数的加减乘除算出,所以在整数点中构造不出60度的角。

【牛客小白月赛69】题解与分析A-F【蛋挞】【玩具】【开题顺序】【旅游】【等腰三角形(easy)】【等腰三角形(hard)】

我们枚举每一个点A,然后枚举其他点作为B,然后再查一下有多少C即可(也就是和A距离等于dist(AB)的点),这里只需保证C的下标小于B的下标,就保证了一个偏序关系,就不会重复计算。

接下来需要将“三点共线”的这样“特殊等腰三角形”减去,我们只需计算有多少这样的“线段”即可。

【牛客小白月赛69】题解与分析A-F【蛋挞】【玩具】【开题顺序】【旅游】【等腰三角形(easy)】【等腰三角形(hard)】

枚举每一个点A,再查一下A'是否存在即可,可以对点做一个桶来判断,因为地图并不大。

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define int long long
using namespace std;

const int maxn = 3009, T = 1000;
const double eps = 1e-6;

struct Point
{
    int x, y;
}p[maxn];

int dist(const Point &u, const Point &v)
{
    int dx = u.x - v.x;
    int dy = u.y - v.y;
    return dx * dx + dy * dy;
}

int cnt[2123456];
bitset<2005> vis[2005];

signed main()
{
    int n;scanf("%lld", &n);
    for(int i = 1;i <= n; ++ i)
    {
        scanf("%lld %lld", &p[i].x, &p[i].y);
        vis[p[i].x + T][p[i].y + T] = true;
    }
    
    
    int ans = 0;
    for(int i = 1;i <= n; ++ i)
    {
        for(int j = 1;j <= n; ++ j)
        {
            if(i == j)continue;
            
            ans += (cnt[dist(p[i], p[j])] ++);
        }
        for(int j = 1;j <= n; ++ j)
        {
            if(i == j)continue;
            
            cnt[dist(p[i], p[j])] = 0;
        }
    }
    int cnt = 0;
    for(int i = 1;i <= n; ++ i)
    {
        for(int j = 1;j <= n; ++ j)
        {
            if(i == j)continue;
            int tx = 2 * p[j].x - p[i].x;
            int ty = 2 * p[j].y - p[i].y;
            if(tx < -500 || tx > 500 || ty < -500 || ty > 500)continue;
            
            if(vis[tx + T][ty + T])cnt ++;
        }
    }
    printf("%lld\n", ans - cnt / 2);
    return 0;
}

? 本文由eriktse原创,创作不易,如果对您有帮助,欢迎小伙伴们点赞?、收藏⭐、留言?

原文链接:https://www.cnblogs.com/eriktse/p/17254354.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:【牛客小白月赛69】题解与分析A-F【蛋挞】【玩具】【开题顺序】【旅游】【等腰三角形(easy)】【等腰三角形(hard)】 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • python数据结构之二叉树的统计与转换实例

    下面是针对“python数据结构之二叉树的统计与转换实例”的详细讲解攻略: 什么是二叉树 二叉树指的是一种树状结构,具有如下特点: 每个节点最多有两个子节点,分别为左子节点和右子节点 左子节点的值比父节点小,右子节点的值比父节点大 二叉树可以是空树,也可以是非空树。 二叉树的遍历 在对二叉树进行操作时,需要对其节点进行遍历。二叉树的遍历方式一般有以下三种: …

    数据结构 2023年5月17日
    00
  • python实现粒子群算法

    Python实现粒子群算法 粒子群算法(Particle Swarm Optimization,PSO)是一种基于群体智能的优化算法,可以用于解决各种优化问题。在Python中,可以使用numpy和matplotlib库实现粒子算法。本文将详细讲解实现粒子群算法的整个攻略,包括算法原理、实现过程和示例。 算法原理 粒子群算法是一种基于群体智能的优化算法,其基…

    python 2023年5月14日
    00
  • 用Python给图像算法做个简单应用界面

    下面是详细讲解“用Python给图像算法做个简单应用界面”的完整攻略,包含两个示例说明。 应用界面的作用 应用界面是一种非常有用的工具,可以帮助用户更方便地使用图像算法。应用界面可以提供以下功能: 显示图像 提供算法选项 显示算法结果 保存算法结果 应用界面可以使用户更轻松地使用图像算法,而不需要编写代码或使用命令行界面。 Python实现应用界面 Pyth…

    python 2023年5月14日
    00
  • python实现梯度法 python最速下降法

    下面是详细讲解“Python实现梯度法和最速下降法”的完整攻略。 梯度法 梯度法是一种常用的优化算法用于求解无约束优化问题。其基本思想是每一步代中,沿着当前的梯度方向进行下降,以望找到函数的最小值点。 下面是一个Python实现梯度法的示例: import numpy as np def gradient_descent(f, df, x0, alpha=0…

    python 2023年5月14日
    00
  • Python实现搜索算法的实例代码

    Python实现搜索算法的完整攻略 搜索算法是计算机科学中的基本算法之一,它的主要目的是在一组数据中查找特定的元素。在Python中,可以使用简单的代码实现常用的搜索算法。本文将详细讲解Python实现搜索算法的过程,并提供两个示例说明。 线性搜索 线性搜索是一种简单的搜索算法,它的基本思想是从一组数据的第一个元素开始,依次比较每个元素,直到找到目标元素或搜…

    python 2023年5月13日
    00
  • Java数据结构之链表的概念及结构

    Java数据结构之链表的概念及结构 链表的概念 链表是一种非顺序存储的容器,它由一个个结点组成,每个结点包含两部分,数据域和指针域。数据域是存储数据的部分,指针域是指向下一个结点的位置。 相比于数组,链表插入和删除操作的时间复杂度更低,但是访问元素时需要遍历整个链表,时间复杂度相对较高。 链表的结构 链表结构包含两个重要的部分:结点和链表。 结点(Node)…

    数据结构 2023年5月16日
    00
  • 深入浅析C语言中堆栈和队列

    深入浅析C语言中堆栈和队列 堆栈(Stack) 堆栈是一种先进后出(Last In First Out,LIFO)的线性数据结构,只允许在一端进行插入和删除操作。堆栈在C语言中常用于函数调用时的参数传递、表达式求值和程序中断处理等场景。 实现堆栈的基本操作 下面是堆栈的基本操作,可以用数组来实现: 初始化 #define MAX_SIZE 100 // 假设…

    数据结构 2023年5月17日
    00
  • PyTorch实现联邦学习的基本算法FedAvg

    PyTorch实现联邦学习的基本算法FedAvg 联邦学习是一种分布式机器学习方法,它可以在不共享数据的情况下训练模型。在本攻略中,我们将介绍如何使用PyTorch实现联邦学习的基本算法FedAvg,提供两个示例来说明如何使用FedAvg算法进行模型训练。 步骤1:了解FedAvg算法 在FedAvg算法中我们需要考虑以下因素: 客户端:客户端是指参与邦学习…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部