BZOJ 2037: [Sdoi2008]Sue的小球(DP)

2037: [Sdoi2008]Sue的小球

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 530  Solved: 282
[Submit][Status][Discuss]

Description

Sue和Sandy最近迷上了一個電腦遊戲,這個遊戲的故事發在美麗神祕並且充滿刺激的大海上,Sue有一支輕便小巧的小船。然而,Sue的目標並不是當一個海盜,而是要收集空中漂浮的彩蛋,Sue有一個祕密武器,只要她將小船劃到一個彩蛋的正下方,然後使用祕密武器便可以在瞬間收集到這個彩蛋。然而,彩蛋有一個魅力值,這個魅力值會隨着彩蛋在空中降落的時間而降低,Sue要想得到更多的分數,必須儘量在魅力值高的時候收集這個彩蛋,而如果一個彩蛋掉入海中,它的魅力值將會變成一個負數,但這並不影響Sue的興趣,因爲每一個彩蛋都是不同的,Sue希望收集到所有的彩蛋。 然而Sandy就沒有Sue那麼浪漫了,Sandy希望得到儘可能多的分數,爲了解決這個問題,他先將這個遊戲抽象成了如下模型: 以Sue的初始位置所在水平面作爲x軸。 一開始空中有N個彩蛋,對於第i個彩蛋,他的初始位置用整數座標(xi, yi)表示,遊戲開始後,它勻速沿y軸負方向下落,速度爲vi單位距離/單位時間。Sue的初始位置爲(x0, 0),Sue可以沿x軸的正方向或負方向移動,Sue的移動速度是1單位距離/單位時間,使用祕密武器得到一個彩蛋是瞬間的,得分爲當前彩蛋的y座標的千分之一。 現在,Sue和Sandy請你來幫忙,爲了滿足Sue和Sandy各自的目標,你決定在收集到所有彩蛋的基礎上,得到的分數最高。

Input

第一行爲兩個整數N, x0用一個空格分隔,表示彩蛋個數與Sue的初始位置。 第二行爲N個整數xi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋的初始橫座標。 第三行爲N個整數yi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋的初始縱座標。 第四行爲N個整數vi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋勻速沿y軸負方向下落的的速度。

Output

一個實數,保留三位小數,爲收集所有彩蛋的基礎上,可以得到最高的分數。

Sample Input

3 0
-4 -2 2
22 30 26
1 9 8

Sample Output

0.000


數據範圍:
N < = 1000,對於100%的數據。 -10^4 < = xi,yi,vi < = 10^4


難點和重點就在於每次移動都要把未來會減少的得分計算進來,具體解題思想可以看這篇論文,說的非常好:http://wenku.baidu.com/view/83d0a76925c52cc58bd6bea8







#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define FOR(i, x, y) for(int i=x;i<=y;i++)
#define LL long long
using namespace std;
const int MAXN = 1000 + 10;
struct Point
{
    double x, y, v;
    bool operator < (const Point& rhs)const
    {
        return x < rhs.x;
    }
}p[MAXN];
int n;
double x0, dp[MAXN][MAXN][2], sum[MAXN];;
int main()
{
    scanf("%d%lf", &n, &x0);
    FOR(i, 1, n) scanf("%lf", &p[i].x);
    FOR(i, 1, n) scanf("%lf", &p[i].y);
    FOR(i, 1, n) scanf("%lf", &p[i].v);
    sort(p + 1, p + 1 + n);
    for(int i=1;i<=n;i++) sum[i] = sum[i-1] + p[i].v;
    FOR(i, 1, n) dp[i][i][0] = dp[i][i][1] = p[i].y - sum[n] * abs(p[i].x - x0);
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i<=n-len+1;i++)
        {
            int j = i + len - 1;
            dp[i][j][0] = max(dp[i+1][j][0] + p[i].y - abs(p[i].x - p[i+1].x) * (sum[i] + sum[n] - sum[j]),dp[i+1][j][1] + p[i].y - abs(p[i].x - p[j].x) * (sum[i] + sum[n] - sum[j]));
            dp[i][j][1] = max(dp[i][j-1][0] + p[j].y - abs(p[j].x - p[i].x) * (sum[i-1] + sum[n] - sum[j-1]),dp[i][j-1][1] + p[j].y - abs(p[j].x - p[j-1].x) * (sum[i-1] + sum[n] - sum[j-1]));
        }
    }
    printf("%.3lf\n", (1.0 * max(dp[1][n][0], dp[1][n][1]) )/ 1000.0);
    return 0;
}



發佈了275 篇原創文章 · 獲贊 11 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章