题解:2018级算法第三次上机 C3-Zexal的浩瀚星辰

题目描述:

样例:

实现解释:

一道结合了火箭发射的贪心题目

知识点:

贪心,优先队列

题目分析:

根据题目描述可知,延迟后时间是正常推进的,也就是假设共有n个火箭,推迟k小时。则在到达k+1小时时,每过一个小时只要火箭没发射完都会有k(如果k大于n就是有剩余数量)个火箭会遭受延迟的损失,显然这是必然的(因为到达k小时前的损失都已经确定了,无法改变)。

那么依据题意只要使得每次这k个火箭的损失最小即可,而如何最小:让其中单位时间损失最大的火箭发射即可,这样一定比发射其他火箭的损失要小。

于是便可得出贪心的状态转移方程:

cost[i] = cost[i-1]+sum(sum既是此时除去最大损失火箭的总损失量)

sum的获取可以利用排序实现,不过考虑到时间问题,还是用优先队列进行最好,边输入边处理便可解决,具体实现可参考完整代码,内含注释。

难点:

即如何获得当前状态的sum,常规来说只需去除损失最大的火箭然后遍历剩余的相加即可。一次优化:利用sum数组和out变量提前存储避免遍历,不过还是需要排序;二次优化:利用优先队列获取最大值,免去排序。

完整代码:

优先队列版(过了):

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
//考虑到数据范围,这里需要用long long进行储存
//表面上看起来没有超范围,但是延迟时间是需要相乘的,因此还是会超过
priority_queue<long long> pq;
long long sum[500010];
long long cost[1000010];
int main()
{
    ios::sync_with_stdio(false);
    int n,k,temp;
    long long p;//中间值记录每个火箭的损失
    long long out;//统计发射出去火箭的损失和
    while(cin >> n >> k)
    {
        memset(cost,0,(n+k+1)*sizeof(long long));
        //按需初始化,减少时间消耗
        sum[0] = 0;//sum需要用到前一个值,此处设0
        out = 0;
        for(int i = 1;i<=k+n;i++)
        {
            if(i <= n)
            {
                cin >> p;
                sum[i] = sum[i-1]+p;
                pq.push(p);
            }
//错误判断1:if(i <= k) if(i <= n) cost[k]+=(k-i+1)*p;
//这种情况第二个else会被编译器认为是i <= n的补集,会出错 

//错误判断2:if(i <= k&&i <= n) cost[k]+=(k-i+1)*p;
//这种情况会导致i > k但i <= n的情况计算被忽略
//即延迟时间小于最后一个发射时间时 

            if(i <= k)//还没到延迟时间时依据p计算延迟时间时这个火箭的损失
            {
                if(i <= n) cost[k]+=(k-i+1)*p;
                //注意火箭只有n个,所以需要判断下
            }
            else//此时说明延迟已过,需要发射火箭
            {
                temp = i>n?n:i;
                //当i>n则应该temp=n以保证每次获取到的为损失的总和
                //这样减去已经发射火箭的损失和就是这次发射的总损失
                out += pq.top();//选择单位损失最高的火箭发射
                pq.pop();
                cost[i] = cost[i-1] + sum[temp] - out;
                //i小时的损失等于i-1小时损失加上这一小时的新损失
                //当前时间本应发射的总损失减去已经发射的总损失即是延迟火箭新产生的总损失

                //out去除形式,本质相同,只是直接在sum处去除(影响也可保留)
                //不过没有out好理解
//                temp = i>n?n:i;
//                sum[temp] -= pq.top();
//                pq.pop();
//                cost[i] = cost[i-1] + sum[temp];
            }
        }
        cout << cost[k+n] << ‘\n‘;
        //延迟时间和总发射时间之和即是所有火箭发射完全的时间
    }
    return 0;
}

数组排序版(TLE):

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
long long p[500010];
long long sum[500010];
//long long cost[1000010];
int main()
{
    ios::sync_with_stdio(false);
    int n,k;
    int temp;
    long long out;
    while(cin >> n >> k)
    {
        long long cost[n+k+1];
        memset(cost,0,sizeof(cost));
        sum[0] = 0;
        for(int i = 1;i<=n;i++)
        {
            cin >> p[i];
            sum[i] = sum[i-1]+p[i];
            if(i <= k) cost[k]+=(k-i+1)*p[i];
        }
        out = 0;
        for(int i = 1;i<=n;i++)
        {
            temp = k+i;
            if(temp > n) temp = n;
            sort(p+1,p+temp+1);
            out += p[temp];
            p[temp] = 0;
            cost[k+i] = cost[k+i-1] + sum[temp] - out;
            //此时out不能省略了,因为sum已经确定了
        }
        cout << cost[k+n] << ‘\n‘;
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/doUlikewyx/p/11780147.html

时间: 2024-10-06 00:54:10

题解:2018级算法第三次上机 C3-Zexal的浩瀚星辰的相关文章

题解:2018级算法第四次上机 C4-最小乘法

题目描述: 样例: 实现解释: 和字符串处理结合的动态规划,个人认为比较难分析出状态转移方程,虽然懂了之后挺好理解的 知识点: 动态规划,字符串转数字 题目分析: 首先按照最基础:依据题意设计原始dp数组,这里根据描可知有三个数需要考虑:数字串开始,数字串结尾和之间插入的乘号数量,因此基础dp[i][j][k],分别为开始,结束脚标和乘号数. 然后推导:考虑到添加乘号,为了使状态转移方程简单,最后固定位置,因此可以考虑每次都在最后插入乘号,插入乘号的位置便可倒序确定.此时数字串的开始位置便可固定

题解:2018级算法第四次上机 C4-商人卖鱼

题目描述: 样例: 实现解释: 需要简单分析的贪心题 知识点: 贪心,自定义排序,提前存储 题目分析: 卖鱼,鱼卖出去需要时间,鱼没被卖出去之前需要吃饲料 则有,如果卖a鱼的话b鱼会吃饲料c份,而卖b鱼a鱼会吃d份,为了消耗更少的饲料,如果c比d小,则应该卖a鱼.而计算上即c = a.t*b.d,d = a.d*b.t. 因此需要做的就是依据上述公式对所有鱼的买卖优先级进行排序(排序的cmp函数实现有进行简单解释),然后按顺序计算需要的饲料数即可. 为了不再遍历计算卖鱼时的花费,这里用total

2016级算法第三次上机-G.Winter is coming

904 Winter is coming 思路 难题.首先简化问题, \(n\) 个0与 \(m\) 个1排成一列,连续的0不能超过x个,连续的1不能超过y个,求排列方法数. 显然会想到这是动态规划.最快想到的方法是 \(dp[i][j][x][y]\) 表示已经有i个北境兵j个野人参与排列,且末尾有x个连续北境士兵或y个连续野人士兵的方案数.这方法显然是正确的,但是光是 \(dp[200][200][10][10]\) 数组已经十分接近本题内存限制了,保证MLE.状态转移方法是大模拟,四层fo

2016级算法第三次上机-B.Bamboo和巧克力工厂

B Bamboo和巧克力工厂 分析 三条流水线的问题,依然是动态规划,但是涉及的切换种类比较多.比较易于拓展到n条流水线的方式是三层循环,外层是第k个机器手,里面两层代表可切换的流水线 核心dp语句:cost[i][k] = min(cost[i][k], cost[j][k-1]+t[j][i]+p[i][k]) 也可以在A题的基础上详细的列出所有可能的路线切割情况然后找到最小值. 注意本题与A题中t的含义不同. 上机时给出的伪代码 //数组从0开始 const int maxx= 510;

2016级算法第三次上机-C.AlvinZH的奇幻猜想——三次方

905 AlvinZH的奇幻猜想--三次方 思路 中等题.题意简单,题目说得简单,把一个数分成多个立方数的和,问最小立方数个数. 脑子转得快的马上想到贪心,从最近的三次方数往下减,反正有1^3在最后撑着保证减完.不好意思这是错的,因为1,27,64,125...等立方数之间并不是倍数关系,不能构成贪心策略.举个反例:96=64+8+8+8+8=64+27+1+1+1+1+1,答案明显是5,而贪心会算到7. 既然不是贪心,那就是DP了,没毛病.先讲一下常规做法吧,是这样想的:相当于把一个数化成几份

2017级算法第三次上机-B.SkyLee逛漫展

ALS 一道动态规划最经典的题目 动态规划实质上其实就是表格法,利用表格来记录每个子问题的解. DP所关注的其实是递归 即一个较小问题的解和一个较大问题的状态转移问题. 其次还要关注的其实还是是初始值的设立,这个决定了后续的递推能否顺利的进行. 还有要思考好dp数组所代表的具体的含义 这样在状态转移的过程中 也可以好一点理解. #include <iostream> #include <algorithm> #include <cstring> using namesp

2016级算法第三次上机-F.ModricWang的导弹防御系统

936 ModricWang的导弹防御系统 思路 题意即为:给出一个长度为n的序列,求出其最长不降子序列. 考虑比较平凡的DP做法: 令\(nums[i]\) 表示这个序列,\(f[x]\) 表示以第\(x\)个数为结尾的最长的不降子序列的长度,状态转移方程为: \[ f[i]=(\max{f[j]}+1) \;\;\;\;\;\;\; \mbox{when $nums[i]<=nums[j]$}\\] f中的最大值即为答案. 时间复杂度\(O(n^2)\),空间复杂度\(O(n)\) 当然也可

2018级算法第三次期末-神秘谜语

作为xxnn晚会的宣传题,请ZH安排一下宣传费用 题目描述 心心廿廿晚会就要开始啦,作为软件学院光辉美丽的化身,春天与喜悦之神,光的拟人化,过去一切沉沦与虚伪的终结者,未来美好与正义的开启者--Alvin辉(朱辉上仙) 他有着旋转乾坤的能力,在晚会的抽奖栏目上,他轻敲响指就可以抽中所有的奖品,有一天他找到了某楠,说出了一个谜语,如果猜对了的话就能把大奖抱回家(不存在的). 谜语是这样的: 有一连串无序的小写字母,某楠需要交换序列中相邻的两个元素.使得原序列变成不上升序列的最少的交换次数,就是谜底

算法第三章上机实验

算法第三章上机实验 数字三角形 给定一个由 n行数字组成的数字三角形如下图所示.试设计一个算法,计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径经过的数字总和最大. #include <iostream> using namespace std; int maxsum(int a[100][100],int n){ int b[100][100]={0}; for(int i=n-1;i>=0;i--){ for(int j=i;j>=0;j--){