bzoj2037 Sue的小球(区间dp,考虑到对未来的贡献)

​​​​​​​​​​​​​​大致意思就是现在你要不断的奔跑到不同的地点去接球,每一秒可以移动一个单位长度,而你接到一个球的动作是瞬间的,收益是y[i]-t*v[i] 然后呢,要求分数最高。

起初看这个题目QWQ完全没有任何思路,大概只能想到......

先按照x排序(记得把起始位置也加进去)

然后令f[l][r]表示收集完l~r的球,最后在l的最大收益

g[l][r]收集完l~r的球,最后在r的最大收益

然后...然后....然后....

我就去看题解了。
好了 进入正题。
首先我们定义

f[l][r]表示收集完l~r的球,最后在l的最小损失

g[l][r]收集完l~r的球,最后在r的最小损失

最后用总收益减去损失

在按照x排完序之后

进行区间dp,由小区间转到大区间

f[l][r]可以从f[l+1][r]和g[l+1][r]转移而来

g[l][r]可以从f[l][r-1]和g[l][r-1]转移而来

我们可以这么理解

每当我们去接下一个球的时候,其他球在向下掉,相当于我们损失了这些的收益

那么时间就是x之差的绝对值,然后提前用前缀和预处理v

就可以直接算出损失了多少收益了

f[l][r]=min(f[l][r],f[l+1][r]+(sum[n]-sum[r]+sum[l])abs(a[l+1].x-a[l].x));
f[l][r]=min(f[l][r],g[l+1][r]+(sum[n]-sum[r]+sum[l])
abs(a[r].x-a[l].x));
g[l][r]=min(g[l][r],f[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[l].x-a[r].x));

g[l][r]=min(g[l][r],g[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[r-1].x-a[r].x));

转移式子就不过多解释了

然后最后用ans-min(f[1][n],g[1][n])再 /1000就行

最后注意初始化的时候 嗯

QWQ我的写法和很多题解都不一样 不过也过了QWQ不太知道是为什么

for (int i=1;i<=n;i++) f[i][i]=abs(a[i].x-start)sum[n],g[i][i]=abs(a[i].x-start)sum[n];

上代码 嗯

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 1010;

struct Node{
	int v,x,y;
};

Node a[maxn];
int f[maxn][maxn]; //i~j接完 最后在i 
int g[maxn][maxn]; // i~j接完,最后在j
int sum[maxn];
int start,n;
double ans;

bool cmp(Node a,Node b)
{
	return a.x<b.x;
}

int main()
{
  n=read();
  start=read();
  memset(f,127/3,sizeof(f));
  memset(g,127/3,sizeof(g));
  for (int i=1;i<=n;i++) a[i].x=read();
  for (int i=1;i<=n;i++) a[i].y=read(),ans+=a[i].y;
  for (int i=1;i<=n;i++) a[i].v=read();
  n++;
  a[n].x=start;
  sort(a+1,a+1+n,cmp);
  for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].v;
  for (int i=1;i<=n;i++) f[i][i]=abs(a[i].x-start)*sum[n],g[i][i]=abs(a[i].x-start)*sum[n];
  for (int i=2;i<=n;i++)
    for (int l=1;l<=n-i+1;l++)
    {
    	int r = l+i-1;
    	f[l][r]=min(f[l][r],f[l+1][r]+(sum[n]-sum[r]+sum[l])*abs(a[l+1].x-a[l].x));
    	f[l][r]=min(f[l][r],g[l+1][r]+(sum[n]-sum[r]+sum[l])*abs(a[r].x-a[l].x));
    	g[l][r]=min(g[l][r],f[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[l].x-a[r].x));
    	g[l][r]=min(g[l][r],g[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[r-1].x-a[r].x));
	}
  ans=ans-min((double)f[1][n],(double)g[1][n]);
  printf("%.3lf",ans/1000); 
  return 0;
}
原文地址:https://www.cnblogs.com/yimmortal/p/10160606.html