牛客编程巅峰赛S1第8场 - 青铜&白银【个人题解】

题目链接:https://ac.nowcoder.com/acm/contest/6776

一、翻滚吧牛牛(一)

牛牛有一个边长为1的正六边形,只要牛牛一推它就可以一直滚下去,正六边形左下角为A,牛牛想知道正六边形翻滚k次A点的轨迹边长是多少呢。如图是正六边形翻滚一次的情况。给定正六边形翻滚次数k,求A点翻滚轨迹长度

牛客编程巅峰赛S1第8场 - 青铜&白银【个人题解】_第1张图片

输入 3
输出 4.955392
备注 1 <= k <= 10^3,返回值与答案误差应小于0.00001

 

分析:

模拟的题目。每次旋转60度,只要知道每次转的扇形的边长即可。有6次,每次的边长是{ 1, 根号3, 2, 根号3, 1, 0 },完了根据边累和长度,累和再乘以π/3.

π的计算可以用下面的式子来写:acos(-1.0), 或者atan(1.0) * 4.

AC代码:

#include 

class Solution {
public:
    /**
     * 
     * @param k int整型 翻滚次数
     * @return double浮点型
     */
    double circumference(int k) {
        double a[6] = {1.0, sqrt(3.0), 2.0, sqrt(3.0), 1.0, 0};
        double ans = 0;
        for (int i = 0; i < k; i++) {
            ans += a[i % 6];
        }
        return acos(-1.0) / 3 * ans;
    }
};

二、牛牛的分配

在牛牛面前有nnn个瓶子,每个瓶子的大小体积都一样,但是每个瓶子内的含水量都不相同。

因为牛牛是个完美主义者,他希望瓶子中的水能够满足他的要求,他的要求是瓶子中的水最少为x。所以他打算对这些瓶子里的水进行重新分配,以满足最多的瓶子中水量大于等于x。

牛牛的分配规则是:每次可以选择多个瓶子,将里面的水平均分配到已选择的瓶子中。

给定n个瓶子和牛牛的对瓶中的水量要求x,以及n个瓶子中的含水量,求最多可以有多少个瓶子满足牛牛的要求?

分析:

从大到小对瓶子里的水量进行排序,然后每选一个瓶子,就平均一下看看平均水量是否大于x,如果是则继续,如果不是就直接break。返回最大的瓶子数。(我为什么就没想到呢?)。因为,如果你再选择比水量比这个瓶子小的,平均水量更低了,所以这个从大到小得到的值是最大的值。

AC代码:

typedef long long LL;
class Solution {
public:
    /**
     * 返回重新分配后,满足牛牛要求的水量的瓶子最多的数量
     * @param n int整型 瓶子的数量
     * @param x int整型 牛牛的对瓶中的水量要求
     * @param a int整型vector 每个瓶子中的含水量
     * @return int整型
     */
    int solve(int n, int x, vector& a) {
        sort(a.begin(), a.end());
        int ans = 0;
        LL sum = 0;
        for (int i = n - 1; i >= 0; i--) {
            sum += a[i];
            if (sum >= 1LL * (n - i) * x) {    //1.为了避免除不尽有精度问题,我们把除换成了乘。
                ans = n - i;                //2.并且加上LL类型,防止数据溢出。
            }
        }
        return ans;
    }
};

三、牛牛构造等差数列:

牛牛和牛妹在玩一个游戏,在他们面前有n个数,他们对每个数可以进行 +1 或 -1 操作,但对于每一个数,该操作最多只能执行一次。

游戏胜利的目标是:使用最少的操作次数,将这几个数构造成一个等差数列。

牛牛特别想赢得游戏,所以他想让你帮他写一个程序,得出最少多少次操作后能使这几个数变成一个等差数列,当然,如果完全不能构造成功,就输出-1。

牛客编程巅峰赛S1第8场 - 青铜&白银【个人题解】_第2张图片

牛客编程巅峰赛S1第8场 - 青铜&白银【个人题解】_第3张图片 分析:

讲解者说她的第一想法是用DP,结果发现不合适。然后想到了枚举。共枚举9种状态。由于确定一个等差数列只需要知道首项和等差即可。我们先确定前两项,然后判断后面是否合适即可。共枚举9中状态。a[0], a[0] + 1, a[0] - 1.      b[0], b[0] + 1, b[0] - 1.共3*3 = 9种,确定首项和等差,然后判断后面的值每一步是否满足值的绝对值最多相差1.如果是,cnt累计起来,然后最终如果找到了结果,就返回一个最小的结果即可。

AC代码:

#include 

class Solution {
public:
    /**
     * 返回最少多少次操作后能使这几个数变成一个等差数列,如果完全不能构造成功,就返回-1
     * @param n int整型 代表一共有n个数字
     * @param b int整型vector 代表这n个数字的大小
     * @return int整型
     */
    int solve(int n, vector& b) {
        // write code here
        if (n <= 2) return 0;    //等差数列本身就是由2个数就可以确定。
        int ans = 0x7fffffff;
        for (int i = -1; i <= 1; i++)           //判断a[0]加上-1, 0, 1的情况
            for (int j = -1; j <= 1; j++) {     //判断a[1] 加上-1,0,1的情况。
                int fst = b[0] + i;       //首项
                int scd = b[1] + j;       //第二项。
                int delta = fst - scd;    //等差
                int cur = scd;            //表示当前值
                int cnt = abs(i) + abs(j);//cnt表示变成等差数列需要多少次变换。初始值为第1位和第2位变换的次数。
                for (int x = 2; x < n; x++) {
                    cur -= delta;         //当前值减去等差后与下一项作比较。
                    if (abs(cur - b[x]) <= 1) {    //如果原来的值最多加1,减1或者值相同则累计这种情况
                       cnt += abs(cur - b[x]);
                    } else {
                        break;
                    }
                    if (x == n - 1) {
                        ans = min(ans, cnt);    //比较获取最大值
                    }
                }
            }
        if (ans < 0x7fffffff) return ans;
        return -1;
    }
};

 

你可能感兴趣的:(比赛)