【牛客小白月赛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进行数独求解详解(一)”的完整攻略。 数独简介 数独是一种逻辑游戏,玩家需要在9×9的网格填入数字,使得每行、每列和每个3×3的网格中的数字都是1-9的不重复数字。数独难度分为简单、中等和困难三个等级。 数独求解算法 数独求解算法的基本思路是使用回溯法,从左到右、从上到下依次填入数字如果填入的数字与已有数字冲突,则回溯到上一个…

    python 2023年5月14日
    00
  • c语言数据结构之并查集 总结

    C语言数据结构之并查集总结 简介 并查集,也称作不相交集合,是一种树型的数据结构。并查集用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。 并查集只有两个操作: find:确定某个元素属于哪个子集。它可以被用来确定两个元素是否属于同一子集。 union:将两个子集合并成同一个集合。 基本实现 以快速查找find和…

    数据结构 2023年5月17日
    00
  • 详解Java集合中的基本数据结构

    详解Java集合中的基本数据结构 Java语言提供了丰富的集合框架,可以帮助我们高效地管理和操作数据。在这个库中,最基本的数据结构有数组、列表、映射和集合。本文将详细讲解Java集合中的基本数据结构。 数组 数组是Java中最基本的数据结构,它可以存储同一种数据类型的多个元素。在Java中,数组属于对象类型。可以通过以下方式来声明一个数组: int[] ar…

    数据结构 2023年5月17日
    00
  • Gauss-Seidel迭代算法的Python实现详解

    下面是详细讲解“Gauss-Seidel迭代算法的Python实现详解”的完整攻略,包括算法原理、Python实现和两个示例。 算法原理 Gauss-Seidel迭代法是一种求解线性方程组的方法,其基本思想是通过不断迭代,逐步逼近方程组的解。算的具体步骤如下: 将线性方程组表示为矩阵形式; 对矩阵进行分解,得下三角矩阵L、对角矩阵D和上三角矩阵U; 将方程表…

    python 2023年5月14日
    00
  • python 普通克里金(Kriging)法的实现

    Python普通克里金(Kriging)法的实现 普通克里金法是一种常用的空间插值方法,它可以用于预测未知位置的值。在本文中,我们将介绍如何使用Python实现通克里金法,并提供两个示例说明。 实现原理 普通克里金法是一种基于统计学的插值,它基于已知点值和它们之间的距离来预测未知点的值。具体实现步骤如下: 首定义一个克里金模,包含变异函数和协方差函数。 然后…

    python 2023年5月14日
    00
  • Python实现的朴素贝叶斯分类器示例

    以下是关于“Python实现的朴素贝叶斯分类器示例”的完整攻略: 简介 朴素贝叶斯分类器是一种常用的机器学习算法,用于分类和预测。在本教程中,我们将介绍如何使用Python实现一个朴素贝叶斯分类器,包括数据预处理、特征提取、模型训练和预测等步骤。 原理 朴素贝叶斯分类器是一种基于贝叶斯定理的分类器,它假设特征之间相互独立,从而简化了计算。在本教程中,我们将使…

    python 2023年5月14日
    00
  • Java数据结构之稀疏数组的实现与应用

    Java数据结构之稀疏数组的实现与应用 什么是稀疏数组 稀疏数组是一种刻画二维数组中许多元素值都为0的特殊数据结构。它可以提高存储空间的利用率,实现对数据的压缩和优化,减少不必要的处理,提升程序的运行效率。 在稀疏数组中,只有非零元素被存储,而这些元素的索引信息和具体数值的信息都会被记录下来。 稀疏数组的实现与应用 实现步骤 创建原始的二维数组,存入多个元素…

    数据结构 2023年5月17日
    00
  • 利用python实现PSO算法优化二元函数

    下面是详细讲解“利用Python实现PSO算法优化二元函数”的完整攻略。 PSO算法 粒子群优化算法(Particle Swarm Optimization,PSO)是一种基于群体智能的化算法,它模拟了鸟群捕食的行为,通过不断调整粒子的位置和速度来寻找最优解。 PSO法的基本思想是将待化问题看作一个多维空间中的搜索问题,将每个解看作空间中的一个粒子通过不断调…

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