SDOI2008 sue的小球

题目链接:戳我

区间DP,设\(dp[i][j][0/1]\)表示收集完\([i,j]\)这个区间的小球之后,现在在左端点(0)或者右端点(1),损失掉的最小收益是多少。

然后初始化只更新离初始点最近的两个点就行了qwq.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 1010
using namespace std;
int n;
double dp[MAXN][MAXN][2],sum[MAXN];
double all,x0;
struct Node{double x,y,k;}node[MAXN];
inline bool cmp(struct Node a,struct Node b){return a.x<b.x;}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%lf",&n,&x0);
    for(int i=1;i<=n;i++) scanf("%lf",&node[i].x);
    for(int i=1;i<=n;i++) scanf("%lf",&node[i].y);
    for(int i=1;i<=n;i++) scanf("%lf",&node[i].k);
    sort(&node[1],&node[n+1],cmp);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+node[i].k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dp[i][j][0]=dp[i][j][1]=1e9;
    bool flag=false;
    for(int i=1;i<=n;i++)
    {
        if(node[i].x>=x0&&flag==false)
        {
            flag=true;
            dp[i][i][0]=dp[i][i][1]=sum[n]*abs(x0-node[i].x);
            dp[i-1][i-1][0]=dp[i-1][i-1][1]=sum[n]*abs(x0-node[i-1].x);
        }
    }
    for(int i=n-1;i>=1;i--)
        for(int j=i+1;j<=n;j++)
        {
            dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(node[i+1].x-node[i].x)*(sum[i]+sum[n]-sum[j]));
            dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(node[j].x-node[i].x)*(sum[i]+sum[n]-sum[j]));
            dp[i][j][0]=min(dp[i][j][0],dp[i][j-1][1]+(2*node[j].x-node[j-1].x-node[i].x)*(sum[i-1]+sum[n]-sum[j-1]));
            dp[i][j][0]=min(dp[i][j][0],dp[i][j-1][0]+(2*node[j].x-2*node[i].x)*(sum[i-1]+sum[n]-sum[j-1]));

            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(node[j].x-node[j-1].x)*(sum[i-1]+sum[n]-sum[j-1]));
            dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(node[j].x-node[i].x)*(sum[i-1]+sum[n]-sum[j-1]));
            dp[i][j][1]=min(dp[i][j][1],dp[i+1][j][0]+(node[i+1].x-2*node[i].x+node[j].x)*(sum[i]+sum[n]-sum[j]));
            dp[i][j][1]=min(dp[i][j][1],dp[i+1][j][1]+(2*node[j].x-2*node[i].x)*(sum[i]+sum[n]-sum[j]));
        }
    for(int i=1;i<=n;i++) all+=node[i].y;
    printf("%.3lf\n",(all-min(1.0*dp[1][n][0],dp[1][n][1]))/1000.0);
    return 0;
}
posted @ 2019-05-16 13:16  风浔凌  阅读(128)  评论(0编辑  收藏  举报