[NOIP模拟]甲虫
题目
题目背景
有一只甲虫处于一根水平的树枝。因为他沉迷数学无法自拔,所以他觉得很像是在 \(x\) 轴上。
在同一根树枝上,还有 \(n\) 滴露水。每滴露水占用 \(m\) 个单位的水分。相对于甲虫的位置,他们的坐标分别是 \(x_1,x_2...x_n\).
显然,这一天将会骄阳似火。每过一个时间单位,就会有一个单位的水分从每一滴露水流失。这只甲虫受尽了烈阳的折磨,以至于每当它碰到一滴露水都能瞬间喝完。在每个时间单位中它能移动一个单位的距离。
所以你要写一个程序,根据露水的坐标,计算出甲虫最多能喝到的水。
输入格式
第一行,两个整数 \(n\) 和 \(m\).
以下 行,每行一个整数,表示露水的坐标 \(x_1,x_2,...x_n\).
输出格式
输出一行,表示甲虫最多能喝到的水.
数据范围
测试点编号 | n |
---|---|
1 | \(\le 10\) |
2~3 | \(\le 25\) |
4 | \(\le 60\) |
5~7 | \(\le 100\) |
8~10 | \(\le 300\) |
题解
\(DP\) 加费用提前计算,首先定义状态 \(f[i][j][0|1]\) 表示甲虫吃了 \([i,j]\) 的水,现在在 左/右 端点的最大贡献.
但是如果我们在状转中加入提前计算的费用,有一个未知量——区间长度.
考虑到 \(n\le 300\),我们可以直接枚举一个区间长度,再做一遍区间 \(DP\),在所有值中取最大的返回即可.
总时间复杂度 \(\mathcal O(n^3)\).
代码
#include<bits/stdc++.h>
using namespace std;
namespace IO{
#define rep(i,l,r) for(int i=l,i##_end_=r;i<=i##_end_;++i)
#define fep(i,l,r) for(int i=l,i##_end_=r;i>=i##_end_;--i)
#define fi first
#define se second
#define Endl putchar('\n')
#define writc(x,c) fwrit(x),putchar(c)
typedef long long ll;
typedef pair<int,int> pii;
template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x<0?-x:x;}
template<class T>inline void getMax(T& x,const T y){x=Max(x,y);}
template<class T>inline void getMin(T& x,const T y){x=Min(x,y);}
template<class T>T gcd(const T x,const T y){return y?gcd(y,x%y):x;}
template<class T>inline T readin(T x){
x=0;int f=0;char c;
while((c=getchar())<'0' || '9'<c)if(c=='-')f=1;
for(x=(c^48);'0'<=(c=getchar()) && c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){
if(x<0)return putchar('-'),fwrit(-x);
if(x>9)fwrit(x/10);putchar(x%10^48);
}
}
using namespace IO;
const int maxn=301;
const int inf=(1<<30)-1;
int x[maxn+5],n,m,op;
inline void Init(){
n=readin(1),m=readin(1);
rep(i,1,n)x[i]=readin(1);
x[++n]=0;
sort(x+1,x+n+1);
rep(i,1,n)if(x[i]==0){op=i;break;}
}
int f[maxn+5][maxn+5][2];
inline int dis(const int i,const int j){return fab(x[i]-x[j]);}
/** @param len 区间的长度*/
inline int get_f(const int len){
rep(l,1,len){
rep(i,Max(1,op-l+1),Min(op,n-l+1)){
int j=i+l-1;
if(i>1){
getMax(f[i-1][j][0],f[i][j][0]+m-dis(i-1,i)*(len-l));
getMax(f[i-1][j][0],f[i][j][1]+m-dis(i-1,j)*(len-l));
}
if(j<n){
getMax(f[i][j+1][1],f[i][j][0]+m-dis(i,j+1)*(len-l));
getMax(f[i][j+1][1],f[i][j][1]+m-dis(j,j+1)*(len-l));
}
}
}
int ret=0;
rep(i,Max(1,op-len+1),Min(op,n-len+1))getMax(ret,Max(f[i][i+len-1][0],f[i][i+len-1][1]));
return ret;
}
signed main(){
// freopen("beetle.in","r",stdin);
// freopen("beetle.out","w",stdout);
Init();
int ans=0;
// 枚举区间的长度
rep(len,2,n){
rep(i,1,n)rep(j,1,n)f[i][j][0]=f[i][j][1]=-inf;
f[op][op][0]=f[op][op][1]=0;
getMax(ans,get_f(len));
}writc(ans,'\n');
return 0;
}