饥饿的奶牛oj上n只有1000,过于水,O(n^2)的算法很容易水过,洛谷上这是一道提高加的题,很难啊,所以要好好拿来练习今天写博客再次复习一下,oi最怕遗忘了。

这道题呢实质是一个区间覆盖的dp,首先是设f[i]表示前i个草地所能获得的最大值,这也就很简单的找到了状态转移方程。

如果当前的前j草地和第i草地不相交f[i]=max(f[i],f[j]+s[i].y-s[i]. x+1);最后所要找的就是max(f[i]);这样一道很简单复杂度为O(n^2)的算法被打出来了。

必须要排序因为在进行判断两个区间是否相交的时候直接用s[i].x>s[i].y,排序的目的很显然是为了让每个判断都能把已判断过的边也直接判断出来,要不有可能一些状态是不合法的转移,这样判断就可以是两个区间或和其他已经累加上的区间是否相交了。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<map>
  4. #include<vector>
  5. #include<iomanip>
  6. #include<cmath>
  7. #include<ctime>
  8. #include<cstring>
  9. #include<string>
  10. #include<algorithm>
  11. #include<queue>
  12. #include<stack>
  13. using namespace std;
  14. inline int read()
  15. {
  16. int x=,f=;char ch=getchar();
  17. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  18. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  19. return x*f;
  20. }
  21. const int maxn=;
  22. int n,ans=,f[maxn];
  23. struct bwy
  24. {
  25. int x,y;
  26. }s[maxn];
  27. int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
  28. {
  29. if(x.x==y.x)return x.y<y.y;
  30. return x.x<y.x;
  31. }
  32. int main()
  33. {
  34. //freopen("1.in","r",stdin);
  35. n=read();
  36. memset(f,,sizeof(f));
  37. for(int i=;i<=n;i++)
  38. s[i].x=read(),s[i].y=read();
  39. sort(s+,s++n,wy);
  40. for(int i=;i<=n;i++)
  41. {
  42. for(int j=;j<i;j++)
  43. if(s[j].y<s[i].x)f[i]=max(f[i],f[j]+s[i].y-s[i].x+);
  44. }
  45. for(int i=;i<=n;i++)
  46. ans=max(ans,f[i]);
  47. printf("%d\n",ans);
  48. return ;
  49. }

这个代码a掉oj上的这道题完全没问题了,洛谷上就TLE了,正常现象。于是考虑到算法的优化。

因为f[i]表示的是第i个草堆所能得到的最大值所以f[i]>=f[j],这就满足了一个单调性,我可以通过去找离当前的f[i]最近的f[j]且不和f[i]这个区间相交来进行不必要再次循环一遍从0到i来更新最优解,这就是策略,至于咋么找那就是二分了快速查找,二分查找找出这个j值从而进行对i的更新。

和chty学长的一番交流发现自己排序错了,因为在查找的时候是要保证f[j].y<f[i].x.所以假如是全部靠左端点排序的话你的mid值后面的区间是可能仅仅是左端点是小于当前的但是呢其他点的右端点很可能就将其全部涵盖所以你判断当前的点的右端点是出现问题的,这就保证不了两个区间是不相交的了。于是采用右端点排序使右端点递增就可以保证其他的点也小于当前的点的左端点了。

所以应该讲右端点排序然后比的时候是f[j].y<f[i].x这样的话之前的右端点就可以全部小于当前的左端点了,不会有上方情况的发生。右端点排序后dp的时候就可以继承i-1的最优解了因为后面的点不可能和最优解相交且和不优解相交,这样就可以保证啦。。。想了好久的问题终于因为这一个排序所解决。

下面是代码二分专属:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<map>
  4. #include<vector>
  5. #include<iomanip>
  6. #include<cmath>
  7. #include<ctime>
  8. #include<cstring>
  9. #include<string>
  10. #include<algorithm>
  11. #include<queue>
  12. #include<stack>
  13. using namespace std;
  14. inline int read()
  15. {
  16. int x=,f=;char ch=getchar();
  17. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  18. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  19. return x*f;
  20. }
  21. const int maxn=;
  22. struct bwy
  23. {
  24. int x,y;
  25. }s[maxn];
  26. int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
  27. {
  28. if(x.y==y.y)return x.x<y.x;
  29. return x.y<y.y;
  30. }
  31. int n,f[maxn],ans=;
  32. int find(int x)
  33. {
  34. int l=,r=x;
  35. while(l+<r)
  36. {
  37. int mid=(l+r)>>;
  38. if(s[mid].y<s[x].x)l=mid;
  39. else r=mid;
  40. }
  41. if(s[r].y<s[x].x)return r;
  42. if(s[l].y<s[x].x)return l;
  43. return -;
  44. }
  45. int main()
  46. {
  47. //freopen("1.in","r",stdin);
  48. n=read();
  49. for(int i=;i<=n;i++)s[i].x=read(),s[i].y=read();
  50. sort(s+,s++n,wy);
  51. for(int i=;i<=n;i++)
  52. {
  53. int j=find(i);
  54. if(j!=-)f[i]=max(f[i-],f[j]+s[i].y-s[i].x+);
  55. else f[i]=max(f[i-],s[i].y-s[i].x+);
  56. }
  57. for(int i=;i<=n;i++)
  58. ans=max(ans,f[i]);
  59. printf("%d\n",ans);
  60. return ;
  61. }

其实呢这道题让学长来看就是一个01背包直接看出来,可能对dp十分的熟悉吧。

这里我采用临街表存相同的点的右坐标加上当前的区间的值即可这样的话每次访问到当前的j(正序循环)如果j连边的话就行更新,当然在更新之前要把上个f[i-1]过继下来因为满足了单调性所以可以这样最好f[m]即为最大值。很简单超快的!

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<map>
  4. #include<vector>
  5. #include<iomanip>
  6. #include<cmath>
  7. #include<ctime>
  8. #include<cstring>
  9. #include<string>
  10. #include<algorithm>
  11. #include<queue>
  12. #include<stack>
  13. using namespace std;
  14. inline int read()
  15. {
  16. int x=,f=;char ch=getchar();
  17. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  18. while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
  19. return x*f;
  20. }
  21. const int maxn=;
  22. int n,m,lin[maxn],ver[maxn],len=,nex[maxn],f[maxn];
  23. void add(int x,int y)
  24. {
  25. ver[++len]=y;
  26. nex[len]=lin[x];
  27. lin[x]=len;
  28. }
  29. struct bwy
  30. {
  31. int x,y;
  32. }s[maxn];
  33. int main()
  34. {
  35. //freopen("1.in","r",stdin);
  36. n=read();
  37. for(int i=;i<=n;i++)
  38. {
  39. s[i].x=read();
  40. s[i].y=read();
  41. m=max(m,s[i].y);
  42. add(s[i].y,s[i].y-s[i].x+);
  43. }
  44. for(int i=;i<=m;i++)
  45. {
  46. f[i]=f[i-];
  47. for(int j=lin[i];j;j=nex[j])
  48. {
  49. f[i]=max(f[i-ver[j]]+ver[j],f[i]);
  50. }
  51. }
  52. printf("%d\n",f[m]);
  53. return ;
  54. }

明知不可为而为之!

dp进阶——饥饿的奶牛的更多相关文章

  1. 题解 P1868 【饥饿的奶牛】

    题目链接:P1868 饥饿的奶牛 题面 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧 ...

  2. codevs 1345 饥饿的奶牛

    1345 饥饿的奶牛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description John养了若干奶牛,每天晚上奶牛都要进食.由于条件比较 ...

  3. BZOJ1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛

    1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 665  Solved: 419 ...

  4. BZOJ 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛( LIS )

    裸的LIS ----------------------------------------------------------------- #include<cstdio> #incl ...

  5. 洛谷P1868 饥饿的奶牛

    P1868 饥饿的奶牛 题目描述 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草.你 ...

  6. 华东交通大学 2019 I 不要666 数位dp进阶

    Problem Description 题库链接 666是一个网络用语,用来形容某人或某物很厉害很牛.而在西方,666指魔鬼,撒旦和灵魂,是不吉利的象征.所以邓志聪并不喜欢任何与6有关的数字.什么数字 ...

  7. 【Luogu】P1868饥饿的奶牛(DP)

    题目链接 话说我存一些只需要按照一个关键字排序的双元素结构体的时候老是喜欢使用链式前向星…… DP.f[i]表示前i个位置奶牛最多能吃到的草.转移方程如下: f[i]=f[i-]; f[i]=max( ...

  8. [LUOGU1868] 饥饿的奶牛 - dp二分

    题目描述 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草.你可以选择任意区间但不能有 ...

  9. [luoguP1868] 饥饿的奶牛(DP)

    传送门 先把所有区间按照左端点排序 f[i]表示区间0~i的最优解 #include <cstdio> #include <iostream> #include <alg ...

随机推荐

  1. 【ARM】arm系列知识框架

    [ARM编程模型] 硬件: 电路原理图 软件: 体系结构, 指令集, 寄存器组 [ARM编程技术] 汇编/C语言 编译, 链接, 烧写和调试 windows: MDK linux  : gcc [AR ...

  2. Spring Mvc 入门Demo

    1.web.xml配置 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns=" ...

  3. headfirst python 01~02

    列表 列表就像是数组 在python 创建一个列表时, 解释器会在内存中创建一个类似数组的数据结构来存储数据, 数据项自下而上(形成一个堆栈), 类似于其他编程语言中的数组. 列表中常用方法: cas ...

  4. Java如何验证电子邮件地址格式?

    在Java编程中,如何验证电子邮件地址格式? 以下示例演示如何使用String类的matches()方法来验证电子邮件地址. package com.yiibai; public class Vali ...

  5. tronado学习

    请求处理程序和请求参数: 原创首发:http://www.cnblogs.com/zxlovenet/p/4128644.html 程序将URL映射到tornado.web.RequestHandle ...

  6. java主线程等待所有子线程执行完毕在执行(常见面试题)

    java主线程等待所有子线程执行完毕在执行(常见面试题) java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个 ...

  7. mysqldump导出数据时,某些表不导出,排除某些表,不导出某些表

    需求说明: 今天一同事问,在通过mysqldump导出数据库的时候,能不能把某些表不导出,或者叫做排除在外呢, 记得应该是可以实现,就搜索了下,通过mysqldump的--ignore-table参数 ...

  8. [Laravel] 14 - REST API: Laravel from scratch

    前言 一.基础 Ref: Build a REST API with Laravel API resources Goto: [Node.js] 08 - Web Server and REST AP ...

  9. Win10系统安装过程小记

    1.网上下载ghost系统http://win10.jysmac.cn/win1064.html 2.使用系统自带的激活工具激活 3.到windows官网下载更新工具更新系统,重新安装https:// ...

  10. 【代码审计】五指CMS_v4.1.0 后台存在SQL注入漏洞分析

      0x00 环境准备 五指CMS官网:https://www.wuzhicms.com/ 网站源码版本:五指CMS v4.1.0 UTF-8 开源版 程序源码下载:https://www.wuzhi ...