本文含有原创题,涉及版权利益问题,严禁转载,违者追究法律责任

  本次是最后一篇免费的考试题解,以后的考试题目以及题解将会以付费的方式阅读,题目质量可以拿本次作为参考

  本来半个月前就已经搞得差不多了,然后给一位神犇orz看(神犇orz都是很忙的!),就一直听取意见修修改改呀拖到了半个月之后,不过这也是为了能够做到完美吧

T1-apple-1s

  第一题是一道贪心的水题

  

  天数只有两天,不是今天吃就是明天吃,我们将 b[i]=min(x[i],y[i])定为基础开心值,也就是说不论哪天吃都至少可以得到这个分数,于是只用考虑在哪天吃可以得到比基础更高的分数

  那么我们将第一天的开心值减去第二天的开心值,得到一个差值,若为正数,则表示第一天比第二天优,若我们在第一天吃,那么除了得到基础的分数以外,还可以得到第一天多出的额外分数。如 x[1]=5,y[1]=3,不论在哪天吃至少可以得到 3 分,若在第一天吃还可以得到额外的 2 分

  则将 b[i] 这个差值按降序排序,然后从前往后贪心即可

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. using namespace std;
  8.  
  9. struct data
  10. {
  11. long long n,a,b,x;
  12. }
  13. a[];
  14. long long n,m,i,ans;
  15. bool cmp(data x,data y)
  16. {
  17. return x.x>y.x;
  18. }
  19. int main()
  20. {
  21. freopen("apple.in","r",stdin);
  22. freopen("apple.out","w",stdout);
  23. cin>>n>>m;
  24. for (i=;i<=n;i++)
  25. {
  26. cin>>a[i].n>>a[i].a>>a[i].b;
  27. a[i].x=a[i].a-a[i].b;
  28. }
  29. sort(a+,a++n,cmp);
  30. for (i=;i<=n;i++)
  31. {
  32. if (m-a[i].n>=)
  33. {
  34. m-=a[i].n;
  35. ans+=a[i].a*a[i].n;
  36. }
  37. else
  38. {
  39. ans+=a[i].a*m+a[i].b*(a[i].n-m);
  40. m=;
  41. }
  42. }
  43. cout<<ans<<endl;
  44. return ;
  45. }

  然后我来讲讲60分的做法,你强行不开 long long 就可以得到60分的高分!

T2-mos-1s

  第二题DP,决策比较难想到,但是代码很容易写,原题是BZOJ2072和POI2004的,但BZOJ把题删了,POI根本上不去……坑爹呐,还是要贴上题目

  先把时间升序排序,依次标号为1~n

  我们考虑两种决策,第一种先让 1 号和 n 号过桥,然后 1 号返回,此时消耗 a[n]+a[1] 的时间,第二种是让 1 号和 2 号过桥,然后 1 号送回火把,n 号再跟 n-1 号过桥,最后 2 号送回火把,这样消耗 a[n]+2*a[2]+a[1] 的时间。显然第一种方案只能送走一个人,第二种方案可以送走两个人

  这两种方案是最优的,但貌似证明比较难,这也导致了决策比较难想

  设 f[i] 为送走到第 i 个人所用的时间,预处理出 f[n]=a[n]+a[1],因为它不存在第二种两个人一起走的方案

  状态转移方程   f[i]=min(a[i]+a[1]+f[i+1],a[i+1]+2*a[2]+a[1]+f[i+2])   i=n-1~3

  目标状态就是 f[3]+a[2]

  这里有一个点要特判,就是 n=1 或 2,此时答案就是 a[n]

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. using namespace std;
  8.  
  9. const int N=;
  10. int n,a[N],f[N];
  11. int main()
  12. {
  13. freopen("mos.in","r",stdin);
  14. freopen("mos.out","w",stdout);
  15. scanf("%d",&n);
  16. int i;
  17. for (i=;i<=n;i++) scanf("%d",&a[i]);
  18. sort(a+,a++n);
  19. if (n==||n==)
  20. {
  21. printf("%d\n",a[n]);
  22. return ;
  23. }
  24. f[n]=a[n]+a[];
  25. for (i=n-;i>;i--) f[i]=min(a[i]+a[]+f[i+],a[i+]+*a[]+a[]+f[i+]);
  26. printf("%d\n",f[]+a[]);
  27. return ;
  28. }

T3-sta-2s

  题目给的是两秒哈,然而极限数据最后被我0.998s跑过了

  这题是BZOJ1131和POI2008的原题,结果跟上一题一样在网上已经失传了

  话说大家都讲这是个树形DP模板题,然而我考场上没有做出来……

  

  设 f[x] 为以 x 为根的所有节点深度和,size[x] 为以 x 为根的树的节点个数+1(也就是后代的个数加上自己),fa[x] 为 x 的父亲节点

  那么转移 f[x]=(f[fa[x]]-size[x])+(n-size[x]),把它按括号拆成两部分看,当根换成x后,对于它的父亲而言 x 节点的深度是少了 1 的,并且对于x的所有后代深度来说深度也都减少了1,即前半部分为原先总的深度 f[fa[x]] 减去因为换根少的深度 size[x]。后半部分也类似,除了x及其后代后的节点 n-size[x],每一个深度都多了1,所以要加上

  size 和 fa 数组用 DFS 预处理出来,我们用 f[1] 作为初始状态,它就是所有深度和,在预处理的时候统计统计,DP 用 BFS 转移

  因为 n 很大,所以 DFS 的时候要手写栈

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<stack>
  8. #include<queue>
  9. using namespace std;
  10.  
  11. const int N=;
  12. stack<int> s;
  13. queue<int> q;
  14. int next[N*],first[N],v[N*],d[N],size[N],fa[N],j[N];
  15. long long f[N],k;
  16. bool g[N];
  17. inline void read(int &re)
  18. {
  19. char ch=getchar();
  20. re=;
  21. while (ch>=''&&ch<='')
  22. {
  23. re=re*+ch-'';
  24. ch=getchar();
  25. }
  26. }
  27. int main()
  28. {
  29. freopen("sta.in","r",stdin);
  30. freopen("sta.out","w",stdout);
  31. int i,x,n,m;
  32. read(n);
  33. for (i=;i<n;i++)
  34. {
  35. read(x);
  36. read(v[i]);
  37. next[i]=first[x];
  38. first[x]=i;
  39. v[i+n-]=x;
  40. next[i+n-]=first[v[i]];
  41. first[v[i]]=i+n-;
  42. size[i]=;
  43. }
  44. size[n]=;
  45. s.push();
  46. j[]=first[];
  47. fa[]=-;
  48. while (!s.empty())
  49. {
  50. x=s.top();
  51. for (;j[x];j[x]=next[j[x]])
  52. if (!fa[v[j[x]]])
  53. {
  54. fa[v[j[x]]]=x;
  55. k=d[v[j[x]]]=d[x]+;
  56. f[]+=k;
  57. j[v[j[x]]]=first[v[j[x]]];
  58. s.push(v[j[x]]);
  59. break;
  60. }
  61. if (!j[x])
  62. {
  63. s.pop();
  64. size[fa[x]]+=size[x];
  65. }
  66. }
  67. q.push();
  68. m=;
  69. while (!q.empty())
  70. {
  71. x=q.front();
  72. q.pop();
  73. for (i=first[x];i;i=next[i])
  74. {
  75. if (g[v[i]]) continue;
  76. g[v[i]]=;
  77. q.push(v[i]);
  78. k=n-size[v[i]]*;
  79. f[v[i]]=f[x]+k;
  80. if (f[v[i]]>f[m]||(f[v[i]]==f[m]&&v[i]<m)) m=v[i];
  81. }
  82. }
  83. printf("%d\n",m);
  84. return ;
  85. }

T4-tet-1s

  BZOJ1106与POI2007的原题,BZOJ又把它删掉了T.T

  考试的时候我用了一个奇奇怪怪的方法把它做出来了,虽然不是正解,但是可以A,还跑得挺快

  

  首先我们肯定是每次找最近的两个数字,然后通过交换把它们消去,如 1…2…1…2 这种情况先消去1还是先消去2的结果是一样的

  设原栈为A,新建一个栈为B,每次将A栈顶元素取出丢进B里,如果B内已有相同元素,根据其距离B栈顶的距离更新答案,然后在栈中消去该数字。如果B内没有的话就压进栈,并且记录其位置,这样不断循环直到A为空为止

  证明自己脑补一下(其实可以用“反正”法)

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<stack>
  8. using namespace std;
  9.  
  10. stack<int> a,b,c;
  11. int n,i,x,ans;
  12. bool f[];
  13. int main()
  14. {
  15. freopen("tet.in","r",stdin);freopen("tet.out","w",stdout);
  16. scanf("%d",&n);
  17. for (i=;i<=n*;i++) scanf("%d",&x),a.push(x);
  18. while (!a.empty())
  19. {
  20. x=a.top();
  21. a.pop();
  22. if (f[x])
  23. {
  24. while (b.top()!=x) c.push(b.top()),b.pop(),ans++;
  25. b.pop();
  26. while (!c.empty()) b.push(c.top()),c.pop();
  27. }
  28. else f[x]=,b.push(x);
  29. }
  30. printf("%d\n",ans);
  31. return ;
  32. }

T5-bags-1s

  RQNOJ 123,http://www.rqnoj.cn/problem/123

  不得不说,RQNOJ的机子跑得好慢呀,5*10的数据范围本地跑 0.2s,服务器上愣是把我卡掉了,最后只好写了一份 Pascal 交上去

  本地跑

  

  OJ上跑

  

  咳咳,言归正传

  普通的背包是求出最优的那一种方案,方程转移是 f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]),相当于把 2 个变量经比较后丢到 1 个变量里,也就是 k=1 时的情况。而现在我们需要求最优的前 k 组方案,那么可以把数组再增加一维,变成把 2k 个变量经比较后丢进 k 个数里,也就是 2 个线性表丢进 1 个线性表里,由于线性表内数据是单调下降的,则可以按照归并排序的做法做

  实现操作中还可以滚掉第一维,那么 j 就要递减枚举

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. using namespace std;
  8.  
  9. const int V=,K=,maxint=;
  10. int f[V][K],g[K];
  11. int main()
  12. {
  13. freopen("bags.in","r",stdin);
  14. freopen("bags.out","w",stdout);
  15. int i,j,n,m,s,ans=,q1,q2,k,w,v;
  16. scanf("%d%d%d",&m,&s,&n);
  17. for (i=;i<=s;i++)
  18. for (j=;j<=m;j++) f[i][j]=-maxint;
  19. f[][]=;
  20. for (i=;i<=n;i++)
  21. {
  22. scanf("%d%d",&w,&v);
  23. for (j=s;j>=w;j--)
  24. {
  25. if (f[j-w][]<) continue;
  26. q1=q2=;
  27. for (k=;k<=m;k++)
  28. if (f[j-w][q1]+v>f[j][q2]) g[k]=f[j-w][q1++]+v;
  29. else g[k]=f[j][q2++];
  30. for (k=;k<=m;k++) f[j][k]=g[k];
  31. }
  32. }
  33. for (i=;i<=m;i++) ans+=f[s][i];
  34. printf("%d\n",ans);
  35. return ;
  36. }

  其实本来还准备了 3 道题的,不过那三道一道是国家集训队的作业题,一道是省队的考试题,最后一道是有版权的原创题(发了的话XXX会Heck我的QuQ)

  那也就不能放进“水题”合集了吧

  另外,所有题目均有数据出售,具体价格如下:

  T1:RMB 1.0    T2:RMB 0.5    T3:RMB 0.5    T4:RMB 0.5    T5:自己到 OJ 上测去

  如需购买请联系作者

  联系方式:http://www.cnblogs.com/hadilo/p/5932395.html

DP+贪心水题合集_C++的更多相关文章

  1. NOIP水题合集[3/未完待续]

    NOIP2008pj传球游戏 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球, ...

  2. USACO(含training section)水题合集[5/未完待续]

    (1) USACO2.1 Ordered Fractions 枚举 排序即可,注意1/1 #include<iostream> #include<cstdio> #includ ...

  3. LightOJ 1166 Old Sorting 置换群 或 贪心 水题

    LINK 题意:给出1~n数字的排列,求变为递增有序的最小交换次数 思路:水题.数据给的很小怎么搞都可以.由于坐标和数字都是1~n,所以我使用置换群求循环节个数和长度的方法. /** @Date : ...

  4. 秋招如何抱佛脚?2022最新大厂Java面试真题合集(附答案

    2022秋招眼看着就要来了,但是离谱的是,很多同学最近才想起来还有秋招这回事,所以纷纷临时抱佛脚,问我有没有什么快速磨枪的方法, 我的回答是:有! 说起来,临阵磨枪没有比背八股文更靠谱的了,很多人对这 ...

  5. Codeforces Round #197 (Div. 2) (A、B、C、D、E五题合集)

    A. Helpful Maths 题目大意 给一个连加计算式,只包含数字 1.2.3,要求重新排序,使得连加的数字从小到大 做法分析 把所有的数字记录下来,从小到大排序输出即可 参考代码 #inclu ...

  6. DP入门水题集

    HDU 1087 Input contains multiple test cases. Each test case is described in a line as follow:N value ...

  7. 【专业找水题】状压dp最水题,没有之一

    题目链接 现在代码能力没上升,倒是越来越会找水题了(比例题还水的裸题你值得拥有) 这网站不是针对竞赛的,所以时空限制都很宽松 然后就让我水过去了 对于每个点,包括自己的前m个元素是否取都是一种状态,所 ...

  8. 搜索水题四连发_C++

    特别声明:以下题目有部分为原创题,涉及版权问题,不得转载,违者追究 法律责任! 话说这是一套神题,只有你想不到,没有你做不到 题目更正后比 Pascal 跑得还快哈~ 一道特别裸,但是特别坑的搜索题 ...

  9. Codeforces Round #374 (div.2)遗憾题合集

    C.Journey 读错题目了...不是无向图,结果建错图了(喵第4样例是变成无向就会有环的那种图) 并且这题因为要求路径点尽可能多 其实可以规约为限定路径长的拓扑排序,不一定要用最短路做 #prag ...

随机推荐

  1. Linq工具篇(1)——使用LinqPad

    学习Linq,有一个非常强大的工具,那就是LinqPad,具体功能有多强大就不说了,网上百度一下就可以知道,百闻不如一见,用用就知道,在网上下载一个绿色版的,无需安装,直接运行,界面如下: 具体功能, ...

  2. [推荐]spring cloud 详解

    http://blog.csdn.net/column/details/15197.html

  3. 【习题集锦】全国青少年NOIP培训教材 ISBN 978-7-305-04246-1

    目录 第一章 回溯法 找路径问题 递归代码: procedure find(k:integer); {找第K步的可能性} begin if 到目的地 {表示一条路已找出} then begin 输出路 ...

  4. LSTM调参经验

    0.开始训练之前先要做些什么? 在开始调参之前,需要确定方向,所谓方向就是确定了之后,在调参过程中不再更改 1.根据任务需求,结合数据,确定网络结构. 例如对于RNN而言,你的数据是变长还是非变长:输 ...

  5. git - work flow

    git status – Make sure your current area is clean. git pull – Get the latest version from the remote ...

  6. LCA(最近公共祖先)——dfs+ST 在线算法

    一.前人种树 博客:浅谈LCA的在线算法ST表 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 题解博客:http://www.cnblogs.com/Miss ...

  7. APP与智能手表是如何通信的【本文摘抄自深圳尚锐科技】

    APP与智能手表是如何通信的 1. Android 与服务器的通信方式主要有两种,一种是http 通信 ,一种是socket 通信. 两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请 ...

  8. [LeetCode] 65. Valid Number(多个标志位)

    [思路]该题题干不是很明确,只能根据用例来理解什么样的字符串才是符合题意的,本题关键在于几个标志位的设立,将字符串分为几个部分,代码如下: class Solution { public: strin ...

  9. SQL SERVER 实用命令集锦

    1.根据关键字查询库中的存储过程,返回符合条件的存储过程名称 select distinct object_name(id) from syscomments where id in (select ...

  10. 二分查找 Binaryserach

    二分查找: 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升 ...