干草堆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-14 23:01
已编辑
中国地质大学(武汉) Java
CUG芝士圈:虽然是网上的项目,但最好还是包装一下,然后现在大部分公司都在忙校招,十月底、十一月初会好找一些。最后,boss才沟通100家,别焦虑,我去年暑假找第一段实习的时候沟通了500➕才有面试,校友加油
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务