生活随笔
收集整理的這篇文章主要介紹了
【LuoguP2466】[SDOI2008] Sue的小球
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接
題目描述
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各自的目標,你決定在收集到所有彩蛋的基礎上,得到的分數最高。
題解
這題和LuoguP1220 關路燈簡直是一道題。
只是把數據變成了實數,然后稍微把最后的結果的求法改了一下,但主體部分一毛一樣。
做了關路燈這題應該秒A不是嗎?
進入正題。
為了方便,我們新加一個蛋,x=x0,y=v=0
這樣就免去了判斷人在哪。
然后我們可以把求總和最大改為每個蛋的分數降低總和最少。
我們拿掉的egg一定是一段連續的吧,因為我們經過了就會拿走。
那么容易想到這是一個區間dp。
并且我們發現拿完一個區間的egg后要么是在左端點,要么是在右端點。
于是設dp[i][j][0/1]表示我把i到j的蛋全拿了,讓后我在左端點還是右端點dp[i][j][0/1]表示我把i到j的蛋全拿了,讓后我在左端點還是右端點
讓后直接就枚舉區間長度和左端點就開始dp了。中間雖然有很多不合法狀態,但對答案不產生任何影響,所以直接安心轉移就行了(具體看代碼)。
時間復雜度O(n2)O(n2)
代碼如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<cstring>
#include<set>
#define min(a,b) ((a)<(b)? (a):(b))
#define max(a,b) ((a)>(b)? (a):(b))
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
int x=
0;
char ch=getchar();
int t=
1;
for(;ch>
'9'||ch<
'0';ch=getchar())
if(ch==
'-') t=-
1;
for(;ch>=
'0'&&ch<=
'9';ch=getchar()) x=(x<<
1)+(x<<
3)+(ch-
48);
return x*t;
}
const int N=
1e3+
10;
struct egg{
double x,y;
double v;
inline bool operator <(egg b)
const{
return x<b.x;}
}a[N];
typedef double db;
typedef long long ll;
db dp[N][N][
2];
ll sum[N];
int n;
double x0;
int main()
{n=read();x0=
1.000*read();db Sum=
0;
for(
register int i=
1;i<=n;i++) a[i].x=
1.000*read();
for(
register int i=
1;i<=n;i++) a[i].y=
1.000*read(),Sum+=a[i].y;
for(
register int i=
1;i<=n;i++) a[i].v=
1.000*read();n++;a[n].x=x0;a[n].y=
0;a[n].v=
0;sort(a+
1,a+
1+n);
register int P;
for(
register int i=
1;i<=n;i++)
if(a[i].x==x0&&a[i].y==
0&&a[i].v==
0) {P=i;
break;}
for(
register int i=
1;i<=n;i++) sum[i]=sum[i-
1]+a[i].v;db INF=
1e10;
for(
register int i=
0;i<=n+
1;i++){
for(
register int j=i;j<=n+
1;j++){dp[i][j][
0]=dp[i][j][
1]=dp[j][i][
0]=dp[j][i][
1]=INF;}}dp[P][P][
0]=dp[P][P][
1]=
0;
for(
register int D=
2;D<=n;D++){
for(
register int l=
1;l+D-
1<=n;l++){
register int r=l+D-
1;
register db tot=sum[n]-sum[r]+sum[l];dp[l][r][
0]=min(dp[l+
1][r][
0]+(a[l+
1].x-a[l].x)*tot,dp[l+
1][r][
1]+(a[r].x-a[l].x)*tot);tot=sum[n]-sum[r-
1]+sum[l-
1];dp[l][r][
1]=min(dp[l][r-
1][
0]+(a[r].x-a[l].x)*tot,dp[l][r-
1][
1]+(a[r].x-a[r-
1].x)*tot);}}db ans=min(dp[
1][n][
1],dp[
1][n][
0]);ans=(Sum-ans)/
1000.000;
printf(
"%.3lf",ans);
}
總結
以上是生活随笔為你收集整理的【LuoguP2466】[SDOI2008] Sue的小球的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。