有一个 nh(n+h) 做法求帮忙看一下
查看原帖
有一个 nh(n+h) 做法求帮忙看一下
704089
kkxacj楼主2025/6/13 18:17

rt,说下做法,由于要一个单调不增的序列,还要记相邻的间隔之类的。

考虑不记间隔,枚举第 ii 个位置,当前柱子高度总和为 jj 时,上次放的柱子高度为 fi,jf_{i,j},若 fi,j=0f_{i,j} = 0 就是无法达到,虽然可能有多个可行 fi,jf_{i,j},不过显然我们可以记 fi,jf_{i,j} 最小的,这是没影响的,原因很显然,如果我下一个想选大于 fi,jf_{i,j} 的但不行,那不如在之前选。

然后可能有多次更新 fi,jf_{i,j},不过从第二次开始,每次都至少让 fi,jf_{i,j} 变小 11,所以复杂度是 nh2nh^2 的。

然后还要枚举 fi,jf_{i,j},复杂度是 n2hn^2h 的。

自己跑了一下数据时间跟期望时间差不多,转移细节就不说了看代码吧。

代码如下:

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;
}
2025/6/13 18:17
加载中...