sue的小球

说实话 这题我是看了各位大佬题解并询问班上大佬同学

写出来的。

这题要用区间动规,也就是用f[i][j] 表示一段区间的状态 然后进行状态转移。

首先思考 下标 i、j是表示横坐标吗?

显然,如果维护横坐标,那么数组开不下。

那么,就只能维护第几个小球。即先把小求按横坐标排序,再标上序号(相当于离散化)

然后思考 维护什么,怎么转移

  1. 如果维护这段区间得分,那么,显然,当你要区间合并时,你无法合并,因为这段区间的得分在随着时间变化,你不会知道当你合并时,它还剩多少得分
  2. 那么如果维护这段区间走过时,它旁边的小球失去了多少分呢?我们这样想 :合并时,用小区间合并小区间,即多个不重叠的 并且连续的 小区间 合并成一个大区间;小区间维护, 走完这段区间后, 它旁边的小球失去了多少分 那么, 这样, 在合并时, 则不受别的区间干扰;

现在,解决了,dp维护什么 的问题;

*接着,让我们模拟走的过程(就是dp方程)。*

如果我们要走i到j这段连续的小球(注意 i、j不是起点与终点,是范围),我们有许多走法,但总结起来,就是由两种走法组成

  1. 从i走到j(反向同理)
  2. 从i走到j,并且从j回到i(反向同理)

所有的走法,均由这两种重复形成。

扫描二维码关注公众号,回复: 2296269 查看本文章

如果考虑更细,我们发现

  1. 从i走一步,到j;
  2. 从i返回,到之前的一点

构成了所有走法

dp思路隐约出来了

dp[i][j],会有两种意思:

  1. 从i到j这一段的蛋全捡了,而且,我在i
  2. 从i到j这一段的蛋全捡了,而且,我在j

为了避免歧义,用两个方程,解释。

f[i][j] :走完i到j,在i处

g[i][j] :走完i到j,在j处

怎么转移

试想:f[i][j]怎么来的?
你可能会说:i到j的走法那么多,得到的方法太多了。回想刚刚说的,就两种
1. 上一步为f[i-1][j],
往左边走一步,得到f[i][j]。
2.
上一步为g[i-1][j],往左跨过这段区间,走到i
得到f[i][j];

同理,g[i][j];

转移代码f[i][j]

““`
f[i][j]=min(f[i][j],f[i+1][j]+(js(1,i)+js(j+1,n))*(ball[i+1].x-ball[i].x));
f[i][j]=min(f[i][j],g[i+1][j]+(js(1,i)+js(j+1,n))*(ball[j].x-ball[i].x));

““`
转移代码g[i][j]


g[i][j]=min(g[i][j],g[i][j-1]+(js(1,i-1)+js(j,n))*(ball[j].x-ball[j-1].x));
g[i][j]=min(g[i][j],f[i][j-1]+(js(1,i-1)+js(j,n))*(ball[j].x-ball[i].x));

代码中js(a,b) 函数指a到b这一段小球的下落速度之和(事先用前缀和维护)
乘上移动距离的位置差(就是时间差),得到f[i][j]这一段丧失的得分


*最后,附上代码*


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define MAXN 1005
#define rg register
using namespace std;
struct zjy{
    int x,y,v;
}ball[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN],tot;
int x0,n,pre[MAXN];
bool cmp(zjy x,zjy y){return x.x<y.x;}
int js(int l,int r){return pre[r]-pre[l-1];}
int main(){
    memset(f,0x3f,sizeof(f));
    memset(g,0x3f,sizeof(g));
    ios::sync_with_stdio(false);
    cin>>n>>x0;
    for(rg int i=1;i<=n;++i)cin>>ball[i].x;
    for(rg int i=1;i<=n;++i)cin>>ball[i].y,tot+=ball[i].y;
    for(rg int i=1;i<=n;++i)cin>>ball[i].v;
    ball[++n].x=x0;
    sort(ball+1,ball+n+1,cmp);
    for(rg int i=1;i<=n;++i)pre[i]=pre[i-1]+ball[i].v;
    for(rg int i=1;i<=n;++i)if(ball[i].v==0&&ball[i].x==x0)f[i][i]=0,g[i][i]=0;
    for(rg int k=1;k<n;++k)for(rg int i=1,j=i+k;i<=n&&j<=n;++i,j=i+k){
        f[i][j]=min(f[i][j],f[i+1][j]+(js(1,i)+js(j+1,n))*(ball[i+1].x-ball[i].x));
        f[i][j]=min(f[i][j],g[i+1][j]+(js(1,i)+js(j+1,n))*(ball[j].x-ball[i].x));
        g[i][j]=min(g[i][j],g[i][j-1]+(js(1,i-1)+js(j,n))*(ball[j].x-ball[j-1].x));
        g[i][j]=min(g[i][j],f[i][j-1]+(js(1,i-1)+js(j,n))*(ball[j].x-ball[i].x));
    }
    printf("%.3lf",(tot-min(f[1][n],g[1][n]))/1000.0);
}

猜你喜欢

转载自blog.csdn.net/jh_2002/article/details/80638796