干草堆tower

一个很好的dp.

显然最优的方案一定是最瘦的情况,从前往后是没有转移性质的,也不符合dp的最优解转移.

那么考虑从后往前转移,定义:

fif_i表示到了第ii个的{最小宽度是多少,高度是多少},因为到了ii最小宽度的情况下,高度是最高的,顺带记录下高度即可.

转移很显然:

fi.first=sufisufj,fi.second=fj.second+1{f_i.first=suf_i-suf_j,fi.second=f_j.second+1}。当sufi>=sufj+fj.firstsuf_i>=suf_j+f_j.first

由上面的贪心我们知道,jj越小越好.而且fj.first+sufjf_j.first+suf_j一定是要递增的.不然单调性就不成立.

还有一个细节就是并不是你推进来就可以把前面所有比你小的全部删了,因为可能下一个的sufisuf_i不一定不小于当前的sufnow+fnowsuf_{now}+f_{now}.所以我们要保留最后一个元素.

那么我们只要拿一个双端队列记录下转移就好了.

复杂度就可以到达O(N)O(N).

code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+5;

int w[N],suf[N];
pair<int,int>f[N];

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	for(int i=n;i>=1;i--)
		suf[i]=suf[i+1]+w[i];
	deque<int>q;
	int x=n+1;
	for(int i=n;i>=1;i--)
	{
		f[i]={suf[i],1};
		while(q.size()&&f[q.front()].first+suf[q.front()]<=suf[i])	
		{
			f[i].first=suf[i]-suf[q.front()],f[i].second=f[q.front()].second+1,x=q.front(),q.pop_front();
		}
		q.push_front(x);
		while(q.size()&&f[q.back()].first+suf[q.back()]>f[i].first+suf[i])	q.pop_back();
		q.push_back(i);
	}
	
	printf("%d\n",f[1].second);
	return 0;
}
全部评论

相关推荐

10-25 12:05
已编辑
湖南科技大学 Java
若梦难了:我有你这简历,已经大厂乱杀了
点赞 评论 收藏
分享
10-15 15:00
潍坊学院 golang
跨考小白:这又不是官方
投递拼多多集团-PDD等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务