rt,说下做法,由于要一个单调不增的序列,还要记相邻的间隔之类的。
考虑不记间隔,枚举第 i 个位置,当前柱子高度总和为 j 时,上次放的柱子高度为 fi,j,若 fi,j=0 就是无法达到,虽然可能有多个可行 fi,j,不过显然我们可以记 fi,j 最小的,这是没影响的,原因很显然,如果我下一个想选大于 fi,j 的但不行,那不如在之前选。
然后可能有多次更新 fi,j,不过从第二次开始,每次都至少让 fi,j 变小 1,所以复杂度是 nh2 的。
然后还要枚举 fi,j,复杂度是 n2h 的。
自己跑了一下数据时间跟期望时间差不多,转移细节就不说了看代码吧。
代码如下:
code
#include<bits/stdc++.h>
using namespace std;
#define getchar() (p1 == p2 && (p2 = (p1 = buf1) + fread(buf1, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf1[1 << 23], *p1 = buf1, *p2 = buf1, ubuf[1 << 23], *u = ubuf;
namespace IO
{
template<typename T>
void read(T &_x){_x=0;int _f=1;char ch=getchar();while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();_x*=_f;}
template<typename T,typename... Args>
void read(T &_x,Args&...others){Read(_x);Read(others...);}
const int BUF=20000000;char buf[BUF],to,stk[32];int plen;
#define pc(x) buf[plen++]=x
#define flush(); fwrite(buf,1,plen,stdout),plen=0;
template<typename T>inline void print(T x){if(!x){pc(48);return;}if(x<0) x=-x,pc('-');for(;x;x/=10) stk[++to]=48+x%10;while(to) pc(stk[to--]);}
}
using namespace IO;
const int N = 580,M = 580,Z = 580*572;
int n,a[N],o,v[M],o2,mx[M],f[2][Z],o1,v2[Z],v3[Z],sum,z1,x,y,st[M],cnt,ny;
//放了前i个位置,总和为j时是合法,合法时最右边的颜色就为f_{i,j}
signed main()
{
// freopen("cup5.in","r",stdin);
// freopen("cup.out","w",stdout);
read(n);
for(int i = 1;i <= n;i++) read(a[i]),sum += a[i],v[a[i]]++;
sort(a+1,a+1+n),o1 = a[n-1];
for(int i = o1;i >= 1;i--) mx[i] = mx[i+1]+v[i+1];//比i大的个数
f[1][a[n-1]+a[n]] = a[n-1],x = 1; o = a[n]+(n-1)*a[n-1];//o是值的上界
for(int i = 2;i < n;i++)
{
x = (i&1),y = !x; cnt = 0; o2 = 0;
for(int z = 1;z <= o1;z++) if(v[z] && i >= mx[z]) st[++cnt] = z;//这次能选Ta,那至少前面的位置足够放比Ta大的
for(int z = 0;z <= o;z++)
if(f[y][z])
{
ny = f[y][z];
f[x][z+ny] = ny;
for(int k = 1;z+st[k] <= o && k <= cnt && st[k] < ny;k++)
f[x][z+st[k]] = st[k];//由于z从小到大枚举,z越大k越小
f[y][z] = 0;
}
}//复杂度预估:n^2h+h^2*n,即o*(n+h)
//每次冲突f_{i,j}至少变小1,最多变h次
for(int j = sum;j <= o;j++)
if(f[x][j]) print(j-sum),pc(' ');//小转化,直接减去总和就是能接住的大小了
flush();
return 0;
}