欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

牛客编程巅峰赛S1第6场 - 黄金&钻石&王者(总结)

程序员文章站 2022-03-16 13:09:15
牛客编程巅峰赛S1第6场 - 黄金&钻石&王者(总结)A:牛牛爱奇数题意有一个由n个元素组成的数组,牛牛想要将所有的数都变成奇数(即:将所有的偶数都变成奇数),但是他的操作是:一次只能对数组中所有相同元素的值/2。求最少需要操作多少次,使数组中所有元素都变成奇数题解考虑2 4 8这一个数组,如果是从2的元素开始除2,则最终结果为:2/2=1;4/2=2,2/2=1;8/2=4,4/2=2,2/2=1;ans=1+2+3=6;显然是错误的,对于这种情况从大的开始处理显然是...

牛客编程巅峰赛S1第6场 - 黄金&钻石&王者(总结)

A:牛牛爱奇数

题意

有一个由n个元素组成的数组,牛牛想要将所有的数都变成奇数(即:将所有的偶数都变成奇数),但是他的操作是:一次只能对数组中所有相同元素的值/2。

求最少需要操作多少次,使数组中所有元素都变成奇数

题解

考虑2 4 8这一个数组,如果是从2的元素开始除2,则最终结果为:
2/2=1;
4/2=2,2/2=1;
8/2=4,4/2=2,2/2=1;

ans=1+2+3=6;
显然是错误的,对于这种情况从大的开始处理显然是最优的;换句话说,对于已经操作过的值无需再操作,具体往下看。

我们可以使用c++中map集合,用来存某个数字是否被处理过了
以刚刚的数组为例:
遍历到2时,起初mp[2]=0;于是对2进行除2操作,直到不能被2除为止,对于操作过的数,进行标记mp[x]=1,结合下面代码理解。
遍历到4时,起初mp[4]=0;于是对4进行除2操作,4/2=2,由于2已经操作过了,于是继续除2,由于除2为1了,所以结束(需要注意的是,不是中间出现了已经操作过的数就结束循环,而是一直要处理到不能被2整除为止);这里也就只进行了一次操作
遍历到8和遍历到4类似,也只进行了一次操作

于是最终结果为1+1+1=3,分析知道这才是正确结果。

AC代码(cpp)

class Solution {
    map<int,int>mp;
public:
    /**
     * 返回一个数,代表让这些数都变成奇数的最少的操作次数
     * @param n int整型 代表一共有多少数
     * @param a int整型vector 代表n个数字的值
     * @return int整型
     */
    int solve(int n, vector<int>& a) {
        // write code here
        mp.clear();
        int ans=0;
        for(int i=0;i<n;i++){
            int x=a[i];
            while(x%2==0){
                if(mp[x]==0) ans++,mp[x]=1;
                x/=2;
            }
        }
        return ans;
    }
};

B:牛牛摆放花

很无语,为啥这题放在A后面…

题意

n个数组成的数组,每个数有对应的值,现在将这n个数组成一个圆,使得相邻之间数组元素的最大差值尽可能小。

题意

很明显贪心。直接排序,然后有两种方法,一种:从中间往两边分开放,另一种:从两边分别往中间放。
举个栗子:
2 1 1 3 2

首先排序,然后有两种放法,分别为:

  • 第一种放法
    2 1 1 2 3
    这里是从中间往两边放,先放左边再放右边
    对应已经排序的数组下标分别为:
    3 1 0 2 4

  • 第二种放法
    1 2 3 2 1
    这里是从两边往中间放,同样先放左边再放右边
    对应已经排序的数组下标为:
    0 2 4 3 1

通过两种放法可以发现,处理最开始放的最中间两个元素的和最外围的两个元素,对应的位置相差为1外,其他的都相差为2;
于是可以直接先排序后,遍历下数组,对位置为2的数组元素之间进行差值比较。最后对最中间和最外围的进行比较,即可得出答案。

AC代码(cpp)

class Solution {
public:
    /**
     * ​返回按照这些花排成一个圆的序列中最小的“丑陋度”
     * @param n int整型 花的数量
     * @param a int整型vector 花的高度数组
     * @return int整型
     */
    int solve(int n, vector<int>& a) {
        // write code here
        sort(a.begin(),a.end());
        int ans=0;
        for(int i=0;i+2<n;i++){
            ans=max(ans,a[i+2]-a[i]);
        }
        ans=max(ans,a[1]-a[0]);
        ans=max(ans,a[n-1]-a[n-2]);
        return ans;
    }
};

C:星球游戏

题意

n个结点,m条边构成的图,其中牛牛有一定数量的点,牛妹也有一定数量的点,现在问从牛牛中任选一点到牛妹的任意一点的最短距离是多少?
其中给定牛牛拥有的点数,牛妹拥有的点数,给出相应的图结构,已经图的节点数。

题解

考虑这个问题,从牛牛中任选一点到牛妹的任意一点的最短距离,显然是考虑最短路算法(Dijkstra即可)但是如果朴素的Dijkstra的话肯定会超时,于是考虑堆优化的Dijkstra算法,同时图比较大,于是采用向前星存图

然后再想,是不是需要跑p遍dijkstra呢(p为牛牛的结点数),显然这样是没有必要的。
直接设一不存在的结点为终点,例如0,向牛牛所拥有的所有点建单向边,边的权值为0;
设一不存在的点为终点,例如:n+1,牛妹所拥有的所有点向设的点建单向边,边的权值为0。
类似于超级起点和超级终点。

于是直接对超级起点跑一遍Dijkstra即可。

AC代码(cpp)

class Solution {
static const int maxn=1e5+5;
static const int maxm=5e5+5;
static const int inf=0x3f3f3f3f;
struct e{
    int to,nxt,val;
}edge[maxm];
int head[maxn],tot;
int dis[maxn],vis[maxn];
struct node{
    int index,dist;
    bool operator <(const node &b) const{
        return dist>b.dist;
    }
};
public:
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
    }
    void add(int u,int v,int c){
        edge[++tot].to=v;
        edge[tot].val=c;
        edge[tot].nxt=head[u];
        head[u]=tot;
    }
    int dijsktra(int s,int e,int n){
        memset(dis,inf,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[s]=0;
        priority_queue<node> q;
        q.push(node{s,0});
        while(!q.empty()){
            node x=q.top();
            q.pop();
            int u=x.index;
            if(vis[u]) continue;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=edge[i].nxt){
                int v=edge[i].to,c=edge[i].val;
                if(dis[v]>dis[u]+c){
                    dis[v]=dis[u]+c;
                    q.push(node{v,dis[v]});
                }
            }
        }
        return dis[e];
    }
    /**
     *
     * @param niuniu int整型vector 牛牛占领的p个星球的编号
     * @param niumei int整型vector 牛妹占领的q个星球的编号
     * @param path int整型vector<vector<>> m条隧道,每条隧道有三个数分别是ui,vi,wi。ui,vi分别是隧道的两边星球的编号,wi是它们之间的距离
     * @param nn int整型 星球个数n
     * @return int整型
     */
    int Length(vector<int>& niuniu, vector<int>& niumei, vector<vector<int> >& path, int nn) {
        // write code here
        init();
        int s=0,e=nn+1;
        for(int i=0;i<niuniu.size();i++){
            add(s,niuniu[i],0);
        }
        for(int i=0;i<niumei.size();i++){
            add(niumei[i],e,0);
        }
        for(int i=0;i<path.size();i++){
            int u=path[i][0],v=path[i][1],c=path[i][2];
            //cout<<u<<' '<<v<<' '<<c<<endl;
            add(u,v,c);add(v,u,c);
        }
        int ans=dijsktra(s,e,nn);
        if(ans==inf) return -1;
        return ans;
    }
};

本文地址:https://blog.csdn.net/boliu147258/article/details/107586670

相关标签: 牛客