[Contest on 2020.11.24] Beetle

( ext{Description})

传送门

( ext{Solution})

有一个比较显然的结论:如果路过某处有露水就一定会喝。

基于这个结论我们知道每一步一定是走到左/右边露水。

起初想了个这样的 ( ext{DP})(f[i][j])(j) 时刻到 (i) 号露水的最多的水。你会发现不仅时间过不去,状态也无法转移。如果以 (i) 为外循环,那么 (i+1) 无法转移到 (i);如果以 (j) 为外循环,那么会把 (i) 的露水算重。

遇到两边向中间/中间向两边转移的问题就应该想到区间 ( ext{DP}) 啊。我们定义 (f[i][j][k][2]) 为已经覆盖的区间为 ([i,j])(容易发现覆盖区间一定是连续的),时间为 (k),现在在 (i/j) 的最多的水。

然后,你会发现,这个 ( ext{DP}) 根本跑不过第一个部分分((nle 10))!仔细想想,原来这个部分分是留给搜索的,那没事了。

考虑优化时间那一维(其他的好像也不能优化了)。其实我们用时间只是为了计算蒸发了多少露水,将这个计算推到每个露水被喝的时候计算。可以换一个思路,如果我们将运算提前,每走一步就将这一步的距离(即时间)乘上后面还剩多少个露水可以取作为这一步的蒸发多少露水,就可以不用储存时间了。取而代之的是要枚举一共取多少露水,这是为了计算后面还剩多少个露水。

总时间复杂度 (mathcal O(n^3))

( ext{Code})

#include <cstdio>

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}

#include <algorithm>
using namespace std;

const int maxn=305,inf=0x3f3f3f3f;

int n,m,x[maxn],ans,k,flag[maxn][maxn][2],f[maxn][maxn][2];

int DP(int op,int l,int r) {
	if(r-l==k) return 0;
	if(flag[l][r][op]==k) return f[l][r][op];
	flag[l][r][op]=k; f[l][r][op]=inf;
	int pos=(op?r:l);
	if(l^1) f[l][r][op]=Min(f[l][r][op],(x[pos]-x[l-1])*(k-(r-l))+DP(0,l-1,r));
	if(r^n) f[l][r][op]=Min(f[l][r][op],(x[r+1]-x[pos])*(k-(r-l))+DP(1,l,r+1));
	return f[l][r][op];
}

int main() {
	n=read(9),m=read(9);
	rep(i,1,n) x[i]=read(9);
	x[++n]=0;
	sort(x+1,x+n+1);
	int pos;
	rep(i,1,n) if(x[i]==0) {pos=i; break;}
	for(k=1;k<n;++k) ans=Max(ans,m*k-DP(0,pos,pos));
	print(ans,'
');
	return 0;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/14031551.html