F-Ants
Input
Output
Sample Input
2
10 3
2 6 7
214 7
11 12 7 13 176 23 191
Sample Output
4 8
38 207
解题思路:这个题想明白一点就好写了。即蚂蚁的速度是一样的,转身不消耗时间,那么可以将两只相遇时掉头的蚂蚁,看做交错而过,不理会相遇即可。因为掉头与交错而过的时间是一样的。再暴力搜素每一个蚂蚁的位置,如果是最短时间,则比较
它距杆左边的距离与距杆右边的距离取最小,取出最大的最小值,即为所求 。如果是最长时间,比较它与杆左边的距离与杆右边的距离取最大,最后取出最大值。代码如下:
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <map> #include <stack> #include <utility> using namespace std; int const max_n=500; int a[max_n]; int main() { int m,n,t; scanf("%d",&t); while(t--){ cin>>m>>n; for(int i=0;i<n;i++)cin>>a[i]; int minN=0,maxN=0;//最短时间,最长时间 for(int i=0;i<n;i++)minN=max(minN,min(a[i],m-a[i])); for(int i=0;i<n;i++)maxN=max(maxN,max(a[i],m-a[i])); cout<<minN<<" "<<maxN<<endl; memset(a,0,sizeof(a)); } return 0; }
G-Fence Repair
Description
It is universally accknowledged that 泥煤(peat)是一个非常珍贵的收藏品,越大的泥煤收藏价值越高。
一天,王泥煤找到了阿拉伯神灯,也就是阿拉丁神灯的弟弟,他向阿拉伯神灯许了一个愿望,从此获得了一个超能力,可以将两个泥煤合并为更大的泥煤。但是这个能力非常的鸡肋,王泥煤需要支付与这两块泥煤等价值的财富才能将他们合并。
比如:王泥煤把两块价值分别为3和5的泥煤合并,可以得到一块价值为8的泥煤,但是要消耗3+5的财富。
王泥煤想知道,他将手中的n块泥煤合并到只剩下一块之后,最少需要花费多少财富。
Input
第一行为一个整数n(n <= 20000),代表王泥煤拥有的泥煤数量,接下来n行,每行一个整数a_i(1 <= a_i <= 50000),代表每个泥煤的价值
Output
输出包括一行,请告诉王泥煤他需要花费的最少财富。
Sample Input
3
8
5
8
Sample Output
34
解题思路:就是不断选取最小的两块煤进行合成,合成后放入煤堆再找两个最小的,如果取一次排序一次,时间复杂度太高o(n^2),因此要用到优先队列 ,注意使用默认的greater 按升序排序就可以了。注意数据范围,要开long long 代码如下:
#include <iostream> #include <algorithm> #include <queue> #include <stack> #define LL long long using namespace std; int main() { int n,x; LL maxq=0; scanf("%d",&n); priority_queue<LL,vector<LL>,greater<LL> >q; for(int i=0;i<n;i++){scanf("%d",&x);q.push(x);} while(q.size()!=1) { LL a,b; a=q.top();q.pop(); b=q.top();q.pop(); LL c=a+b; q.push(c); maxq+=c; } cout<<maxq<<endl; return 0; }
H-最少拦截系统
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
Input输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
Output对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
Sample Input
8 389 207 155 300 299 170 158 65
Sample Output
2
解题思路:因为不能漏掉任何一个导弹,所以要从第一个导弹开始,构建一个下降子序列;而在构建下降过程中的导弹若高于上一个导弹,则必须要使用新的拦截系统。这题我一开始写的挺复杂的,过了之后看题解,发现自己想复杂了,可以开一个数组,输入一个
导弹高度 ,若高于现在所有的拦截系统的高度,则必须新开一个拦截系统;若有拦截系统能够拦下它,则更新该拦截系统的高度。参考链接:https://blog.csdn.net/sdut_jk17_zhangming/article/details/79292887
代码如下:
#include<stdio.h> int main() { int a[300] = {0},i,n,j,h,m; while(scanf("%d",&n) != EOF) { m = 0; for(i= 0;i <n;i++) { scanf("%d",&h); for(j = 0;j <m;j++) { if(a[j] >= h) break; } if(j <m) a[j] = h; else { a[m] = h; m++; } } printf("%d\n",m); } return 0; }
写题的过程中,有不会的是很正常的,若是自己能写过,就坚持写完,写完找找题解,了解别人的思路再与自己的思路对比,最好能学到最优解。所有做题过程中不要太过于纠结题解问题,关键在于看了有没有学会最优解(或者说相对较好的思路)。
J - Packets
Input
Output
Sample Input
0 0 4 0 0 1
7 5 1 0 0 0
0 0 1 0 1 0
0 0 0 0 0 0
Sample Output
2
1
2
思路:这是一道二维装箱题,而装箱问题一般来说比较复杂,如果针对每一种情况进行精确算法是非常繁琐且容易出错的。在这里我用到了ceil()函数,返回大于或等于表达式值的函数来简化算法。(参考链接http://blog.csdn.net/c20190413/article/details/77396357###)首先看,4×4,5×5,6×6的箱子,很显然这三种箱子没有一个就要占用一个包装袋,6×6的箱子直接占用一个包装袋,而5×5的箱子则可以塞进去11个1×1的箱子,用1×1箱子的个数减去min(a,e*11)(a为1×1箱子个数,e为5×5箱子个数,为表述方便,依次为箱子编号a、b、c、d、e、f);对于一个4×4箱子,可以塞进2×2的箱子5个,若2×2箱子数不足时,可以补充1×1箱子;b-=min(b,d*5),若2×2箱子数不足时则有a-=min(a,4*(d*5-b))。
然后看3×3的箱子,分四种情况,箱子数为4的倍数,除以4余3、余2、余1,3种情况,这里选余2的情况为例子阐述。这时还有若干个1×1箱子若干个2×2箱子,两个3×3箱子;分析易知,此时最多可以放入3个2×2箱子,最少放入6个1×1箱子才能把包装袋填满。首先判断2×2箱子剩余数量有没有3个,不足3个的部分,用1×1箱子补充,不足时有a-=min(a,(3-b)*4);然后进行a-=min(a,6);b-=min(b,3)。其余情况依此类推。使用min函数保证不出现负数。剩余的就是若干个1×1箱子和2×2箱子,使用ceil函数可以很快解决。代码如下:
#include <iostream> #include <algorithm> #include <math.h> #define LL long long int const max_n=20; using namespace std; int main() { int a,b,c,d,e,f; while(1){ cin>>a>>b>>c>>d>>e>>f; if(!a&&!b&&!c&&!d&&!e&&!f)break; int num=0; num=d+e+f; a-=min(a,e*11);//减去应补充e箱子的a箱子 if(b<d*5)a-=min(a,4*(d*5-b));//b箱子不足时,使用a箱子 b-=min(b,d*5);//减去补充d箱子的b箱子 num+=ceil(c/4.0);//向上取整 c%=4; if(c==1){//多余1个3×3的箱子时 if(b<5)a-=min(a,4*(5-b));//先判断b箱子数量是否足够 a-=min(a,7); b-=min(b,5); } else if(c==2){//多余2个3×3的箱子时 if(b<3)a-=min(a,4*(3-b)); a-=min(a,6); b-=min(b,3); } else if(c==3)//多余3个3×3的箱子时 { if(!b)a-=min(a,4); a-=min(a,5); b-=min(b,1); } num+=ceil(b/9.0); b%=9; if(b)a-=min(a,(9-b)*4); num+=ceil(a/36.0); printf("%d\n",num); } return 0; }
N - Stall Reservations
帮助FJ做以下事:
- 使每只牛都有专属时间的最小牛棚数
- 每只牛在哪个牛棚
第 2..N+1行: 第 i+1行 描述了i号奶牛挤奶的起止时间
Lines 2..N+1: 第 i+1行 描述了i奶牛被安排的牛棚
5
1 10
2 4
3 6
5 8
4 7
Sample Output
4
1
2
3
2
4
Hint
这里是一种图示
Time 1 2 3 4 5 6 7 8 9 10其他的也是可能的
Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>
Stall 2 .. c2>>>>>> c4>>>>>>>>> .. ..
Stall 3 .. .. c3>>>>>>>>> .. .. .. ..
Stall 4 .. .. .. c5>>>>>>>>> .. .. ..
思路:这是一道牛奶分栏问题,分栏不算难,难点在于如何描述某只奶牛在哪个牛棚中。有两种贪心策略,一:以最早开始的奶牛进行计算,在该奶牛产奶结束后
选取离这个结束时间最近且的奶牛,安排其进行产奶,直至某个牛的结束时间大于或等于规定时间,开始为下一个牛棚安排;这种策略实际上是以牛棚为出发点,通过使用最少的牛棚让更多的牛产奶,直到所有奶牛都产过奶了;实现要用set或数组,进行一个牛棚的安排后,要对在该牛棚产奶的牛进行删除。二:将奶牛以产奶时间的早晚进行排列,在时间顺序上让每一个奶牛在产奶时间都能有牛棚产奶,若有空闲牛棚,则安排改产奶的奶牛去产奶,若是没有空闲牛棚,就要准备新的牛棚;通过优先队列以及对队列的维护实现。这里我是用了优先队列,实现代码如下:
#include <iostream> #include <algorithm> #include <queue> #include <set> #define LL long long int const max_n=50002; using namespace std; struct Node{ int st,ed,id,stal;//开始时间,结束时间,奶牛编号,牛棚号 bool operator <(const Node &a)const{//这是优先队列中一个排序方式,重载<用来排序,维护优先队列 return a.ed<ed; } }cow[max_n]; bool cmp(Node a,Node b)//结构体比较函数 { if(a.st!=b.st) return a.st<b.st; return a.ed<b.ed; } int main() { int n,a[max_n]; scanf("%d",&n); priority_queue<Node> q; //下标由1开始,方便计算和思考 for(int i=1;i<=n;i++){scanf("%d %d",&cow[i].st,&cow[i].ed);cow[i].id=i;} sort(cow+1,cow+n+1,cmp); cow[0].stal=1,cow[0].ed=0; q.push(cow[0]); int i=1,k=2;//初始化牛棚数为2 while(i<=n) { Node c=q.top(); if(cow[i].st>c.ed)//当某个牛的开始产奶时间大于队列中最早结束时间,即这个牛产奶开始时有空闲牛棚 { q.pop(); cow[i].stal=c.stal; a[cow[i].id]=c.stal; q.push(cow[i]); } else{//没有空闲牛棚,安排新牛棚 cow[i].stal=k; a[cow[i].id]=k++; q.push(cow[i]); } i++; } printf("%d\n",k-1); for(int i=1;i<=n;i++)printf("%d\n",a[i]); return 0; }
O - Yogurt factory
Yucky Yogurt 拥有一个仓库,可以以S (1 <= S <= 100)美分每单位每周的价格储存没用的酸奶。神奇的是,酸奶不会变质。而且仓库十分巨大,可以容纳很多牛奶
Yucky Yogurt每周要交货 Y_i (0 <= Y_i <= 10,000) 单位的酸奶给它的客户。请你帮助奶牛们减少整个 N-week 期间的支出. i周生产的牛奶和之前储存的牛奶都可以用来交i周的货
Input
* 第 2..N+1行:第 i+1 行包括 : C_i 和 Y_i.
Output
Sample Input
4 5
88 200
89 400
97 300
91 500
Sample Output
126900
Hint
第一周生产200单位,全部售出。第二周生产700单位,售出400,储存300.第三周使用储存的300单位。第四周,生产500单位并全部售出
注释:
yucky意为难以下咽的
思路:贪心策略为,在本周的人工成本较低下周时(即生产下周要交货的奶加上存储的钱仍比下周生产牛奶价格低时),在本周多生产下周要交货的牛奶数,并存在仓库里。其他情况,就老老实实生产足够本周交货的奶,因为一般情况下不考虑生产后两周的牛奶加上存两周牛奶的钱比下下周的生产成本低的情况。代码如下:
#include <iostream> #include <algorithm> #define LL long long int const max_n=10002; using namespace std; struct node{ int c,y; }num[max_n]; int main() { int n,s; scanf("%d %d",&n,&s); for(int i=0;i<n;i++)scanf("%d %d",&num[i].c,&num[i].y); int i=0; LL mony=0; while(i<n) { if(num[i].c*num[i+1].y+s*num[i+1].y<num[i+1].c*num[i+1].y) { mony+=num[i].c*num[i+1].y+s*num[i+1].y; num[i+1].y=0; } mony+=num[i].c*num[i].y; i++; } cout<<mony; return 0; }