牛客编程巅峰赛S1第8场

 

目录

翻滚吧牛牛(一)

牛牛的分配

牛牛构造等差数列

playfair:

牛牛摇骰子

反复横跳


 

翻滚吧牛牛(一)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

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

 

示例1

输入

3

输出

4.955392

备注:

1≤k≤1031\leq k\le10^31≤k≤103,返回值与答案误差应小于0.00001

思路:

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

牛牛的分配

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

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

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

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

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

 

示例1

输入

3,7,[9,4,9]

输出

3

说明

一共有3瓶水,容量分别为9 4 9,牛牛希望每瓶水中最少容量为7。所以可以选择这3瓶水,平均分配后每瓶水的含量都大于7,所以满足牛牛要求的瓶子最多的数量为3。

示例2

输入

2,5,[4,3]

输出

0

说明

一共有2瓶水,但是每瓶水的容量都无法满足牛牛的要求,所以即使不管怎么分配,也无法满足牛牛的要求。

备注:

1≤n≤106,代表瓶子的数量1 \leq n \leq 10^{6},代表瓶子的数量1≤n≤106,代表瓶子的数量

1≤x≤109,代表牛牛的对瓶中的水量要求1 \leq x \leq 10^{9},代表牛牛的对瓶中的水量要求1≤x≤109,代表牛牛的对瓶中的水量要求

a1,a2,a3...an(1≤ai≤109)代表每个瓶子中的含水量a_{1},a_{2},a_{3}...a_{n}(1 \leq a_{i} \leq 10^{9})代表每个瓶子中的含水量a1​,a2​,a3​...an​(1≤ai​≤109)代表每个瓶子中的含水量

对于25%的数据,1≤n≤102,1≤x,ai≤103对于25\%的数据,1 \leq n \leq 10^{2},1 \leq x,a_{i} \leq 10^{3}对于25%的数据,1≤n≤102,1≤x,ai​≤103

对于75%的数据,1≤n≤104,1≤x,ai≤106对于75\%的数据,1 \leq n \leq 10^{4},1 \leq x,a_{i} \leq 10^{6}对于75%的数据,1≤n≤104,1≤x,ai​≤106

对于100%的数据,1≤n≤106,1≤x,ai≤109对于100\%的数据,1 \leq n \leq 10^{6},1 \leq x,a_{i} \leq 10^{9}对于100%的数据,1≤n≤106,1≤x,ai​≤109

思路:从大到小排序,取前i个平均值,小于x则不可能继续。


class Solution {
public:
    /**
     * 返回重新分配后,满足牛牛要求的水量的瓶子最多的数量
     * @param n int整型 瓶子的数量
     * @param x int整型 牛牛的对瓶中的水量要求
     * @param a int整型vector 每个瓶子中的含水量
     * @return int整型
     */
    
    int solve(int n, int x, vector<int>& a) {
        // write code here
        sort(a.begin(), a.end(),greater<int>());
        long long sum = 0;
        int ans = 0;
        for(int i=0; i<n; i++){
            sum+=a[i];
            if(sum / (i+1) < x) break;
            ans++;
        }
        return ans;
    }
};

 

牛牛构造等差数列

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

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

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

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

示例1

输入

4,[24,21,14,10]

输出

3

说明

在第一个例子中,牛牛应该对第一个数字+1,对第二个数字-1,对第三个数字+1,而第四个数字应该保持不变。最后,序列就变成了[25,20,15,10],这是一个等差数列且操作次数最少。

示例2

输入

3,[14,5,1]

输出

-1

说明

在第二个例子中,不可能只对其中的数字最多操作一次就得到等差数列。

备注:

1≤n≤105,代表有n个数1\leq n \leq10^{5},代表有n个数1≤n≤105,代表有n个数

b1,b2,...bn(1≤bi≤109),代表这n个数字的大小b_{1},b_{2},...b_{n} (1\leq b_{i} \leq10^{9}),代表这n个数字的大小b1​,b2​,...bn​(1≤bi​≤109),代表这n个数字的大小

对于20%的数据,1≤n≤10,1≤bi≤103对于20\%的数据,1\leq n \leq10, 1\leq b_{i} \leq10^{3}对于20%的数据,1≤n≤10,1≤bi​≤103

对于60%的数据,1≤n≤103,1≤bi≤106对于60\%的数据,1\leq n \leq10^{3}, 1\leq b_{i} \leq10^{6}对于60%的数据,1≤n≤103,1≤bi​≤106

对于100%的数据,1≤n≤105,1≤bi≤109对于100\%的数据,1\leq n \leq10^{5}, 1\leq b_{i} \leq10^{9}对于100%的数据,1≤n≤105,1≤bi​≤109

思路:本来以为是dp,听课以后居然是暴力模拟。根据前两个数求出d,对剩余数字进行判断即可。

class Solution {
public:
    /**
     * 返回最少多少次操作后能使这几个数变成一个等差数列,如果完全不能构造成功,就返回-1
     * @param n int整型 代表一共有n个数字
     * @param b int整型vector 代表这n个数字的大小
     * @return int整型
     */
    int solve(int n, vector<int>& b) {
        // write code here
        int ans = 0x3f3f3f3f;
        for(int i=-1; i<=1; i++)
            for(int j=-1; j<=1; j++){
                int x = b[0] + i;
                int y = b[1] + j;
                int mul = y - x;
                int cnt = abs(i) + abs(j);
                int k;
                int cur = y;
                for(k=2; k<n; k++){
                    cur += mul;
                    if(abs(cur - b[k]) <= 1) cnt += abs(cur - b[k]);
                    else break;
                }
                if(k == n) ans = min(ans, cnt);
            }
        if(ans < 0x3f3f3f3f) return ans;
        return -1;
    }
};

playfair:

模拟,不知道playfair如何排列可自行百度。

 

牛牛摇骰子

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

牛牛非常擅长摇骰子,不管给他一个什么样的骰子他都能准确的掷出他想要的那一面。现在有一个四面体骰子,四个面分别是四个整数0,3,7,11。牛牛在玩一个游戏。牛牛初始在一个数轴的原点,每当他摇出一个数字x,他可以自行选择向左走x步或者向右走x步。牛牛想知道他最少摇多少次骰子可以从原点到达坐标为p的点。

现在一共有N次询问,请你返回从0点到询问的每一个坐标arr[i]所需要摇筛子的最小次数。

 

示例1

输入

[1,4,14]

输出

[3,2,2]

说明

从0到1最少需要摇3次骰子(0->7->4->1)(走法不唯一,比如0->11->4->1也只需要掷3次骰子)

从0到4最少需要摇2次骰子(0->7->4)

从0到14最少需要摇2次骰子(0->7->14)

示例2

输入

[6,25]

输出

[2,3]

说明

从0到6最少需要摇2次骰子(0->3->6)

从0到25最少需要摇3次骰子(0->7->18->25)

思路:明显0不会用,尽量多用11,但需要对余为2的情况进行特判,因为13 = 3 + 7 + 3,先走11的话会增加步数。

class Solution {
public:
    /**
     * 把所有询问的答案按询问顺序放入vector里
     * @param arr int整型vector 要查询坐标的数组
     * @return int整型vector
     */
    vector<int> MinimumTimes(vector<int>& arr) {
        // write code here
        int steps[11] = {0,3,4,1,2,3,2,1,2,3,2};
        vector<int > ans;
        for(int i=0; i<arr.size(); i++){
            if(arr[i] % 11 == 2 && arr[i] != 2) ans.push_back(2+arr[i]/11);
            else ans.push_back(arr[i]/11 + steps[arr[i] % 11]);
        }
        return ans;
    }
};

 

反复横跳

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

题意

 

牛牛在某著名游戏公司接了一项任务,已知游戏中有n个点,任意两个点之间由具有一定长度的双向通道连接,并且任意两个点之间有且仅有一条路径使其可以相互到达。牛牛现在的任务为:需要在游戏中操控人物从任意一点作为起点出发,所有的点至少经过一次,可以在任意一点停止交付任务,请问牛牛最少需要操控人物走多远。

输入

第一个参数为 nnn,1≤n≤100,0001\leq n \leq 100,0001≤n≤100,000

第二个参数为大小为 n−1n-1n−1 的点对 (ui,vi)(u_i, v_i)(ui​,vi​) 的集合 EdgeEdgeEdge ,其中 (ui,vi)(u_i, v_i)(ui​,vi​) 表示结点 uiu_iui​ 与结点 viv_ivi​ 之间有一条边,1≤ui,vi≤n1\leq u_i, v_i \leq n1≤ui​,vi​≤n

第三个参数为大小为 n−1n-1n−1 的整数集合 fff ,其中 fif_ifi​ 表示第 iii 条边的长度,1≤fi≤100,0001\leq f_i \leq 100,0001≤fi​≤100,000

输出

最短距离

示例1

输入

5,[(1,2),(2,3),(3,4),(2,5)],[39,48,54,100]

输出

280

说明

 

从 4 号点出发,路径为 4 - 3 - 2 - 1 - 2 - 5。

思路:树的直径以外的边都要走两遍。

/**
 * struct Point {
 *	int x;
 *	int y;
 * };
 */
typedef long long ll;
const int N = 100000 + 10;
int h[N],e[N*2],ne[N*2],idx=0,w[N*2];
int vis[N];
ll sum;
int point;
ll ans;

class Solution {
public:
    /**
     * 最短距离
     * @param n int整型 
     * @param Edge Point类vector 
     * @param val int整型vector 
     * @return long长整型
     */
    void add(int a, int b, int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    void dfs(int u, int fa, int dis){
        if(dis > ans){
            ans = dis;
            point = u;
        }
        for(int i = h[u]; i != -1; i = ne[i]){
            int j = e[i];
            if(j != fa){
                dfs(j, u, dis+w[i]);
            }
        }
    }
    
    long long solve(int n, vector<Point>& Edge, vector<int>& val) {
        memset(h, -1, sizeof h);
        for(int i=0; i<n-1; i++){
            int a = Edge[i].x;
            int b = Edge[i].y;
            int c = val[i];
            sum += c;
            add(a,b,c);
            add(b,a,c);
        }
        sum*=2;
        dfs(1,0,0);
        dfs(point,0,0);
        return sum-ans;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值