[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;
}
posted @ 2020-11-29 09:56  Arextre  阅读(114)  评论(0编辑  收藏  举报