题目描述
题解
O(n3)
的dp随便搞搞
g(i)表示将i~n都用完的最后一层的最小宽度
f(i)表示将i~n都用完的最大高度
可以发现f和g的决策是相同的,也就是说,使最后一层宽度最小也就同时使高度最大了
O(n2)
的转移是只要找到第一个满足的就直接转移(因为前缀和一定是不降的)
然后很显然这个决策是有单调性的(i->i-1)
于是可以在每一次转移之后二分一下这个点可以转移到的有哪些点
又因为是n..1转移,所以拿一个数据结构直接覆盖就好了
代码
O(n3)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 1005
int n,ans;
int w[N],s[N],f[N][N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&w[i]),s[i]=s[i-1]+w[i];
for (int i=1;i<=n;++i)
for (int j=1;j<=i;++j)
{
for (int k=1;k<j;++k)
if (s[i]-s[j-1]<=s[j-1]-s[k-1])
f[i][j]=max(f[i][j],f[j-1][k]);
++f[i][j];
}
for (int i=1;i<=n;++i)
ans=max(ans,f[n][i]);
printf("%d\n",ans);
}
O(n2)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100005
int n,w[N],s[N],f[N],g[N],d[N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&w[i]),s[i]=s[i-1]+w[i];
for (int i=n;i>=1;--i)
for (int j=i+1;j<=n+1;++j)
if (g[j]<=s[j-1]-s[i-1])
{
g[i]=s[j-1]-s[i-1];
f[i]=f[j]+1;
d[i]=j;
break;
}
printf("%d\n",f[1]);
}
O(nlogn)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100005
int n,w[N],s[N],f[N],g[N],d[N];
int pt[N*4],delta[N*4];
void pushdown(int now,int l,int r,int mid)
{
if (delta[now])
{
pt[now<<1]=delta[now<<1]=delta[now];
pt[now<<1|1]=delta[now<<1|1]=delta[now];
delta[now]=0;
}
}
void change(int now,int l,int r,int lr,int rr,int v)
{
int mid=(l+r)>>1;
if (lr<=l&&r<=rr)
{
pt[now]=v;
delta[now]=v;
return;
}
pushdown(now,l,r,mid);
if (lr<=mid) change(now<<1,l,mid,lr,rr,v);
if (mid+1<=rr) change(now<<1|1,mid+1,r,lr,rr,v);
}
int query(int now,int l,int r,int x)
{
int mid=(l+r)>>1;
if (l==r) return pt[now];
pushdown(now,l,r,mid);
if (x<=mid) return query(now<<1,l,mid,x);
else return query(now<<1|1,mid+1,r,x);
}
int find(int l,int r,int x,int j)
{
int mid,ans=0;
while (l<=r)
{
mid=(l+r)>>1;
if (x<=s[j-1]-s[mid-1]) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&w[i]),s[i]=s[i-1]+w[i];
change(1,1,n,1,n,n+1);
for (int i=n;i>=1;--i)
{
d[i]=query(1,1,n,i);
g[i]=s[d[i]-1]-s[i-1];
f[i]=f[d[i]]+1;
int l=find(1,i-1,g[i],i);
if (l) change(1,1,n,1,l,i);
}
printf("%d\n",f[1]);
}