省赛训练题(HDU4968,HDU4970,HDU4864)
来源:互联网 发布:python绝技用的2还是3 编辑:程序博客网 时间:2024/06/06 08:27
省赛训练,关键还是心态问题,心态放平,才能有高效发挥。
这一套题整体感觉质量还是挺好的,各种考验思维的题目,确实很有收获。
按顺序码了前三题,那就让我们来分析一下
A.Improving the GPA
思路:拿到题目后,第一思路就是贪心,压分数的上下值肯定就能得到最值结果。不过,两头的特殊数据就成了比较棘手的问题,考虑分数两边扩展不会影响结果,而扩展到最边上时由于端点的特殊性就可以得到最优值。
于是极限存放60和100,之后贪心其余的步骤。对于贪心的过程,由单步贪心进化到时时贪心。然后对于均分过高或过低的情况单独考虑。
不过对于60和100的数量问题上确实出了不少的问题,最终还是考虑不周而最终报废。
后来经研究发现,既然贪心就完全可以贪心得彻底一点,先将所有数据都处理成60(或100),经以上分析这两个值越多越好。然后对于多余(或不足)的数据,开始依次补进(或消去),直至85(或69),因为进一步的处理不会对分产生任何影响,因此将85(或69)作为为换点标志。
最后就是需要注意,均分过高或过低的情况,由于这种情况下,除最后一个数据外所有值都被设为85(或69),所以最后的结果一定过高(或过低),不过并不影响最终结果,直接按最值100(或60)处理即可。
由此可见,确实贪心过程需要明确的思路和冷静的大脑,不需要将过程复杂化,尽量找出较为普适的同一方程。
最后附上AC代码以及悲催狂WA代码(变量以w开头,位于注释部分),而两个程序结果(***开头为被WA的程序数据)差异经命令行比较(fc)结果如下图。
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>using namespace std;double getscore(int x){ if(x<=69&&x>=60) { return 2.0; } else if(x<=74&&x>=70) { return 2.5; } else if(x<=79&&x>=75) { return 3.0; } else if(x<=84&&x>=80) { return 3.5; } else if(x<=100&&x>=85) { return 4.0; } return false;}int main(){ int n,t,score; while(scanf("%d",&t)!=EOF) { /*double wscore[110]; for(int i=60;i<=69;i++) { wscore[i] = 2.0; } for(int i=70;i<=74;i++) { wscore[i] = 2.5; } for(int i=75;i<=79;i++) { wscore[i] = 3.0; } for(int i=80;i<=84;i++) { wscore[i] = 3.5; } for(int i=85;i<=100;i++) { wscore[i] = 4.0; }*/ while(t--) { scanf("%d%d",&score,&n); double maxscore,minscore; int totalscore = score * n; int lastmaxscore = totalscore - 60 * n; maxscore = 2.0 * (double)(n); int maxid = n; while(lastmaxscore) { if(lastmaxscore > 25 && maxid > 1) { lastmaxscore -= 25; maxscore += 2.0; } else { if(lastmaxscore > 40) { maxscore += 2.0; } else { maxscore = maxscore + getscore(lastmaxscore + 60) - 2.0; } lastmaxscore = 0; } maxid--; } maxscore /= (double)(n); int lastminscore = 100 * n - totalscore; minscore = 4.0 * (double)(n); int minid = n; while(lastminscore) { if(lastminscore > 31 && minid > 1) { lastminscore -= 31; minscore -= 2.0; } else { if(lastminscore > 40) { minscore -= 2.0; } else { minscore = minscore + getscore(100 - lastminscore) - 4.0; } lastminscore = 0; } minid --; } minscore /= (double)(n); printf("%.4f %.4f\n",minscore,maxscore); /* int wn; double k; k = (double)(score); wn = n; //max double wmaxsum = k*(double)(wn); int wnmax = wn; int wm60 = (int)(((89.0-k)*(double)(wn))/29.0); double wmaxs = (double)(wm60)*2.0; if(k>=85) { wmaxs = 4.0; } else { wmaxsum -= (double)(wm60)*60.0; wnmax -= wm60; //int wmaxave = (int)(wmaxsum / (double)(wnmax)); //int wmaxmod = (wmaxave % 5); //int wmaxan = wmaxave - wmaxmod; //wmaxs += wscore[wmaxan]*(double)(wnmax-1); //int maxone = wmaxsum - (double)(wmaxan) * (double)(wnmax - 1); //wmaxs += wscore[maxone]; //wmaxs /= double(wn); //wmaxsum -= (double)(wm60)*60.0; //wnmax -= wm60; while(wnmax>1) { int wmaxave = (int)(wmaxsum / (double)(wnmax)); int wmaxmod = wmaxave % 5; int wmaxan = wmaxave - wmaxmod; wmaxs += wscore[wmaxan]; wmaxsum -= (double)(wmaxan); wnmax--; } wmaxs += wscore[(int)(wmaxsum)]; wmaxs /= (double)(wn); } //min double wminsum = k*(double)(wn); int wnmin = wn; int wm100 = (int)(((k-65.0)*(double)(wn))/35.0); double wmins = (double)(wm100)*4.0; if(k<=69) { wmins = 2.0; } else { wminsum -= (double)(wm100)*100.0; wnmin -= wm100; while(wnmin>1) { int wminave = (int)(wminsum / (double)(wnmin)); int wminmod = 4 - (wminave % 5); int wminan = wminave + wminmod; wmins += wscore[wminan]; wminsum -= (double)(wminan); wnmin--; } wmins += wscore[(int)(wminsum)]; wmins /= (double)(wn); //int wminave = (int)(wminsum / (double)(wnmin)); //int wminmod = 4 - (wminave % 5); //int wminan = wminave + wminmod; //wmins += wscore[wminan]*(double)(wnmin-1); //int minone = wminsum - (double)(wminan) * (double)(wnmin - 1); //wmins += wscore[minone]; //wmins /= double(wn); } printf("*****%.4f %.4f\n",wmins,wmaxs); */ } } return 0;}
B.Killing Monsters
思路:塔防打怪兽问题,题目很清晰,就是区间线段型数据覆盖处理问题。一开始考虑到用树状数组可以降低求和的时间,然而却发现求和之前,将区间数据分配到对应点上就是个很麻烦的问题。而且,对于测试数据较多的情况,完全可以处理全部点,然后作为静态数据来处理,这就免去了反复运算维护的麻烦,将求和过程变成了独立的操作。
那么,现在最大的问题就是如何处理这些数据数据。
或许,这就有点数学导数的思维了,或者可以说信号里面冲激与阶跃的思想。将区间端点作为突变点来处理,存入第一个attack数组,第二个数组hurt对第一个attack数组进行累加,由突变向总值转变,得到每点的对应伤害值,最后引入第三个blood数组,从后往前累加求和,计算出后项累加和。三个数组的计算是三个相互独立的过程,因此相当巧妙地将时间复杂度降到了线性的O(n),完美解决。
当然,这种思维对于以后处理区间线段数据也会有很好的启示作用。
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>using namespace std;const int maxn = 1e5+10;long long attack[maxn];long long hurt[maxn];long long blood[maxn];int main(){ int n,m,k; while(scanf("%d",&n)!=EOF) { if(n==0) { break; } memset(attack,0,sizeof(attack)); scanf("%d",&m); for(int i=0;i<m;i++) { int l,r,d; scanf("%d%d%d",&l,&r,&d); attack[l] += d; attack[r+1] -= d; } long long temphurt = 0; for(int i=1;i<=n;i++) { temphurt += attack[i]; hurt[i] = temphurt; } blood[n] = hurt[n]; for(int i=n-1;i>=1;i--) { blood[i] = blood[i+1] + hurt[i]; } scanf("%d",&k); int sum = 0; for(int i=0;i<k;i++) { long long h; int x; scanf("%lld%d",&h,&x); if(h>blood[x]) { sum++; } } printf("%d\n",sum); } return 0;}
C.Task
思路:求解最优值,又是一道典型的贪心问题,乍一看有点类似于线性规划。如果只有一维因素,那肯定将最重要的任务分配给最强力的机器。
然而,当问题引入二元时,就不那么简单了,如果仅仅简单的区分两个变量的重要性来排序,当一维变量来排序,就会可能忽略一种很普遍的极端情况(高效高能机器处理中效低能任务,中效中能机器却无法处理低效高能任务)。
所以,开始考虑分别贪心的思路。
首先,当然还是按主次因素将任务和机器从大到小排序。
对于任务和机器两个对象,由于最终要计算与任务相关的金额,所以考虑将任务作为遍历对象。
如果分别遍历的话,O(n^2)的时间复杂的确实难以接受,于是开始考虑优化方法。
于是想到每次将满足第一变量时间效率的机器单独提出处理,这样所有机器都只会被处理一遍,时间复杂度被降为O(n+n)。
而对于被提取出的机器,找出满足要求的第二变量机器功能最小的机器,由于第一变量肯定满足无需再考虑,这样就可以给别的任务留出更高能的机器。然而很尴尬的问题是,就这么个找第二变量最小的满足功能的机器,也可能会成为一个长达O(n)的过程,而最坏情况又一次被降到了无法接受的O(n^2)。
仔细分析,发现,对于被提取出的机器,它的第一变量已经没有任何存在需要了(肯定满足),而两个变量之间的对应关系也就不那么重要了。分析输入数据可以发现,第二变量的取值范围只有100,那么就完全可以将所得机器的第二变量单独处理到一个大小仅为100的level数组中,通过数组计数来实现机器第二变量与任务的匹配,成功将时间复杂的降为O(n*100),完美AC
最后就是数组遍历的过程中细心点,谨防数组越界就好了
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>using namespace std;typedef struct PRO{ int x; int y;}Pro;bool cmp(const Pro &x1,const Pro &x2){ if(x1.x>x2.x) { return true; } else if(x1.x==x2.x) { if(x1.y>x2.y) { return true; } } return false;}const int maxn = 1e5+10;Pro task[maxn];Pro machine[maxn];int level[105];int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(level,0,sizeof(level)); for(int i=0;i<n;i++) { scanf("%d%d",&machine[i].x,&machine[i].y); } sort(machine,machine+n,cmp); for(int i=0;i<m;i++) { scanf("%d%d",&task[i].x,&task[i].y); } sort(task,task+m,cmp); int sum = 0; long long money = 0; for(int i=0,j=0;j<m;j++) { while(machine[i].x>=task[j].x&&i<n) { level[machine[i].y]++; i++; } for(int k=task[j].y;k<=100;k++) { if(level[k]>0) { level[k]--; sum++; money += 500 * task[j].x + 2 * task[j].y; break; } } } printf("%d %lld\n",sum,money); } return 0;}
- 省赛训练题(HDU4968,HDU4970,HDU4864)
- hdu4970
- hdu4968
- hdu4970
- hdu4864(贪心)
- hdu4864 Task(贪心)
- hdu4864(贪心)
- HDU4864
- HDu4864
- HDU4864
- hdu4968(矩阵快速幂)
- HDU4864 Task (2014多校第一场D题)
- HDU4970 Killing Monsters (2014多校第九场第11题)
- 【HDU4968】一道水题的4种艹法
- Improving the GPA(hdu4968)dfs
- hdu4970(后缀和,标记法的区间更新)
- hdu4970 Killing Monsters(模拟塔防游戏)
- hdu4968(选n个物品恰好装满的背包)
- Oracle 12C 新特性之move (非分区表)table online
- Python学习手册(第二部分)
- 深度学习基础系列(四)之 用 python 实现 KNN 算法
- Android Video视频播放
- asp.net
- 省赛训练题(HDU4968,HDU4970,HDU4864)
- Vue初体验(一),最简单的Vue示例
- 深度学习之各种优化算法
- MySQL
- Linux根文件之系统制作流程
- loadrunner监视windows和linux资源
- Linux文件管理(3)——文本编辑vi/vim
- dubbo提供方与消费方的三种连接方式
- A*