We need water!
(water.c/cpp/pas)
描述 Description
这个岛可以用一根数轴来表示。这根数轴上某些地方有露水。 一开始每个地方的露水都
是 同样多的。随着时间推移,露水会 不断蒸发。对于每一滴露水, 每一单位时间会使它失
去一单位的水。莫诺现在在数轴的 0 位置上。他每单位时间可以走一单位距离。当他到达某
一个露水的时候,他可以瞬间采集完该点的全部露水。动作的先后顺序是:采集 - 移动 - 露
水蒸发 - 采集 - 移动„„。如果 0 位置有露珠,可以直接取。
问莫诺最多能采集到多少露水。
完成此题你将得到 100 分作为帮助莫诺的奖励。
输入格式 Input Format
第一行两个整数 n 和 m 表示有 n 个露水,每个露水一开始含有 m 单位水。
接下来 n 行每行一个整数表示第 i 个露水的位置。
输出格式 Output Format
输出只有一行表示莫诺最多能采集到的水数。
样例输入 Sample Input
3 15
6
-3
1
样例输出 Sample Output
25
数据规模 Data Limitation
100%的数据,1<=N<=300,
1<=m<=1,000,000,-10,000<=x1,x2...xn<=10000。Xi≠Xj.
【题解】
这道题目和关路灯较为相似,但是我们还需要枚举取的露水的个数,然后在做类似关路灯的DP,f [ j ][ k ][ 0/1 ] 表示已经取了第j个~第k个露水,最后一次取露水是在j的位置 / k的位置时,所浪费掉(蒸发)的最少的水量,可以得到转移
p表示枚举的露水个数,i 表示当前取的露水个数,j 和 k 枚举取的露水是第j个~第k个,可以得到转移:
f[j][k][0] = min(f[j+1][k][0]+(a[j+1]-a[j]) * (p-i+1), f[j+1][k][1]+(a[k]-a[j])* (p-i+1));
f[j][k][1] = min(f[j][k-1][1]+(a[k]-a[k-1]) * (p-i+1), f[j][k-1][0]+(a[k]-a[j])* (p-i+1));
然后用p*m(总水量)- 最少的浪费掉的水量来更新ans。如果一开始0的位置没有露水,需要先添加一个露水,然后最后再减掉。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=400; int n,m,a[N],f[N][N],g[N][N],ans=0; inline int max(int a,int b) { return a>b?a:b; } int main() { freopen("water.in","r",stdin); freopen("water.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) scanf("%d",&a[i]); a[++n]=0; sort(a+1,a+1+n); int s; for(int i=1; i<=n; i++) if(a[i]==0) { s=i; break; } /*memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g)); f[s][s]=g[s][s]=0; for(int len=2; len<=n; len++) { for(int i=1; i+len-1<=n; i++) { int j=i+len-1; f[i][j]=min(f[i+1][j]+(a[i+1]-a[i])*(n-len+1),g[i+1][j]+(a[j]-a[i])*(n-len+1)); g[i][j]=min(g[i][j-1]+(a[j]-a[j-1])*(n-len+1),f[i][j-1]+(a[j]-a[i])*(n-len+1)); ans=max(ans,(len-1)*m-min(f[i][j],g[i][j])); } }*/ for(int p=1; p<=n; p++) { memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g)); f[s][s]=g[s][s]=0; for(int len=2; len<=p; len++) for(int i=1; i+len-1<=n; i++) { int j=i+len-1; f[i][j]=min(f[i+1][j]+(a[i+1]-a[i])*(p-len+1),g[i+1][j]+(a[j]-a[i])*(p-len+1)); g[i][j]=min(g[i][j-1]+(a[j]-a[j-1])*(p-len+1),f[i][j-1]+(a[j]-a[i])*(p-len+1)); ans=max(ans,(len-1)*m-min(f[i][j],g[i][j])); } } printf("%d ",ans); return 0; }