来自一个弱鸡的随笔单调队列 动态规划
题目链接:http://forioi.com/contest/problem?id=56&pid=9#problem-anchor
g[j]<=s[i]-s[j],即s[j]+g[j]<=s[i],若有 k<j且g[k]+s[k]>=g[j]+s[j]则k永远不可能再转移别人了,因为如果k满足转移条件,那么j也会满足,而j的位置还更加靠后。
因此,我们可以维护一个 g+s值单调递增的单调队列。
每次转移时从单调队列中找到最后一个g[j]+s[j]<=s[i]的位置j,单调队列中j以左的元素从队首出队。
转以后从队尾弹出g[j]+s[j]>=g[i]+s[i]的元素,然后将位置i加入单调队列。
每个元素进出队列各一次,复杂度为O(n)。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,a[maxn],s[maxn],f[maxn],g[maxn],q[maxn],l,r; int main() { scanf("%d",&n); for(int i=n;i;--i) scanf("%d",a+i); for(int i=1;i<=n;++i) s[i]=s[i-1]+a[i]; for(int i=1;i<=n;++i) { while(l<r&&s[q[l+1]]+g[q[l+1]]<=s[i]) ++l; f[i]=f[q[l]]+1; g[i]=s[i]-s[q[l]]; while(l<r&&s[q[r]]+g[q[r]]>=s[i]+g[i]) --r; q[++r]=i; } printf("%d",f[n]); return 0; }
有木有很清爽啊~