饥饿的奶牛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,排序的目的很显然是为了让每个判断都能把已判断过的边也直接判断出来,要不有可能一些状态是不合法的转移,这样判断就可以是两个区间或和其他已经累加上的区间是否相交了。

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
int n,ans=,f[maxn];
struct bwy
{
int x,y;
}s[maxn];
int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
{
if(x.x==y.x)return x.y<y.y;
return x.x<y.x;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
memset(f,,sizeof(f));
for(int i=;i<=n;i++)
s[i].x=read(),s[i].y=read();
sort(s+,s++n,wy);
for(int i=;i<=n;i++)
{
for(int j=;j<i;j++)
if(s[j].y<s[i].x)f[i]=max(f[i],f[j]+s[i].y-s[i].x+);
}
for(int i=;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}

这个代码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的最优解了因为后面的点不可能和最优解相交且和不优解相交,这样就可以保证啦。。。想了好久的问题终于因为这一个排序所解决。

下面是代码二分专属:

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
struct bwy
{
int x,y;
}s[maxn];
int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
{
if(x.y==y.y)return x.x<y.x;
return x.y<y.y;
}
int n,f[maxn],ans=;
int find(int x)
{
int l=,r=x;
while(l+<r)
{
int mid=(l+r)>>;
if(s[mid].y<s[x].x)l=mid;
else r=mid;
}
if(s[r].y<s[x].x)return r;
if(s[l].y<s[x].x)return l;
return -;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
for(int i=;i<=n;i++)s[i].x=read(),s[i].y=read();
sort(s+,s++n,wy);
for(int i=;i<=n;i++)
{
int j=find(i);
if(j!=-)f[i]=max(f[i-],f[j]+s[i].y-s[i].x+);
else f[i]=max(f[i-],s[i].y-s[i].x+);
}
for(int i=;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}

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

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

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
int n,m,lin[maxn],ver[maxn],len=,nex[maxn],f[maxn];
void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
struct bwy
{
int x,y;
}s[maxn];
int main()
{
//freopen("1.in","r",stdin);
n=read();
for(int i=;i<=n;i++)
{
s[i].x=read();
s[i].y=read();
m=max(m,s[i].y);
add(s[i].y,s[i].y-s[i].x+);
}
for(int i=;i<=m;i++)
{
f[i]=f[i-];
for(int j=lin[i];j;j=nex[j])
{
f[i]=max(f[i-ver[j]]+ver[j],f[i]);
}
}
printf("%d\n",f[m]);
return ;
}

明知不可为而为之!

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. ②NuPlayer播放框架之ALooper-AHandler-AMessage底层机制分析

    [时间:2016-09] [状态:Open] [关键词:android,NuPlayer,开源播放器,播放框架,ALooper,AHandler,AMessage] 前文中提到过NuPlayer基于S ...

  2. goldengate–使用filter+@GETENV在线重新初始化指定的table

    goldengate–使用filter+@GETENV在线重新初始化指定的table 转载:http://www.easyora.net/blog/using_filter_getenv_functi ...

  3. Thrift 源码学习一——源码结构

    Thrift 客户端与服务端的交互图 源码结构 传输层 TTransport: TTransport:客户端传输层抽象基础类,read.write.flush.close 等方法 TSocket 与 ...

  4. Linux SD/MMC/SDIO驱动分析_转

    转自:Linux SD/MMC/SDIO驱动分析    https://www.cnblogs.com/cslunatic/p/3678045.html#3053341 一.SD/MMC/SDIO概念 ...

  5. linux基础知识 【转】

    linux目录架构 / 根目录 /bin 常用的命令 binary file 的目錄 /boot 存放系统启动时必须读取的档案,包括核心 (kernel) 在内 /boot/grub/menu.lst ...

  6. 关于指针*前后const代表的意思——记住一个口诀“左内右本”

    记住一个口诀“左内右本”:const出现在*的左边,则说明指针所指向的内容是常量const出现在*的右边,则说明指针本身是常量如果*左右两边都出现const,那么说明指针本事是常量,它所指向的内容也是 ...

  7. Spring配置-数据库连接池proxool[转]

    数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对这个问题提出 ...

  8. Error - SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM

    I find using the following works quite well for SQL min/max dates after many DB related errors: Date ...

  9. Markdown 链接

    如下,方括号显示说明,圆括号内显示网址, Markdown 会自动把它转成链接 [我是百度](https://www.baidu.com/) [我是淘宝](https://www.taobao.com ...

  10. windows 2008 r2 不能启用网络发现

    在win2008 R2里面,不能启用网络发现,查询资料,得知需开启一下三个服务: Function Discovery Resource Publication SSDP Discovery UPnP ...