【简●解】[SDOI2008] Sue的小球

计划着刷DP题结果碰到了这样一道论文题,幸好不是太难


【题目大意】#

口水话有点多,所以就直接放链接。传送门

【分析】#

看到题首先联想到了曾经做过的关路灯。所以先按x值排序,然后进行区间DP

不妨设f1[i][j]f2[i][j]分别表示从起点出发已射落ij这一段彩蛋,当前停留在i点,j点的最大得分v

考虑 f1[i][j],即点i是当前射击的彩蛋,射击的得分与当前时刻挂钩,但 是当前的时刻是不能从f1[i][j]的状态中表示出来的,我们进一步考虑 f1[i][j]的求解。

由于射击i的得分是yitvi,而t等于之前每一步决策移动的时间总和,这样我们就可以把tvi​在之前的移动中就计算,也就是说每次移动都要把未来会减少的得分计算在内。 比如说从f1[i+1][j]推到f1[i][j],即从i+1走到i时除了i+1j这一段彩蛋外,其它的彩蛋都在下落,将这丢失的分数一并计算到从i+1走到i中。由于tvi已经在之前决策时计算,所以射击时直接加上yi即可。

所以可以先用sum[]计算vi的前缀和,然后DP方程:

f1[i][j]=y[i]+max(f1[i+1][j]+Sum(i+1,j)(xi+1xi),f2[i+1][j]+Sum(i+1,j)(xjxi)

f2[i][j]=y[i]+max(f1[i][j1]+Sum(i,j1)(xjxi),f2[i][j1]+Sum(i,j1)(xjxj1)

然后O(n2)过。

【Code】#

Copy
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define ll long long using namespace std; const int MAX = 1000 + 5; const int INF = 0x3f3f3f3f; inline int read(){ int f = 1, x = 0;char ch; do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0'||ch>'9'); do {x = x*10+ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); return f*x; } int n, bj; double x0, f[3][MAX][MAX], sum[MAX]; struct sakura { double x, y, v; }sak[MAX]; inline bool cmp(sakura a, sakura b) { return a.x < b.x; } inline double Sum(int l, int r) { return sum[n] - sum[r] + sum[l - 1]; } inline double ab(double a) { return a < 0 ? -a : a; } int main(){ n = read(); ++n, x0 = read(); sak[1].x = x0, sak[1].y = sak[1].v = 0; for (int i = 2;i <= n; ++i) { sak[i].x = read(); } for (int i = 2;i <= n; ++i) { sak[i].y = read(); } for (int i = 2;i <= n; ++i) { sak[i].v = read(); } sort(sak + 1, sak + 1 + n, cmp); for (int i = 1;i <= n; ++i) { sum[i] = sum[i - 1] + sak[i].v; if (ab(sak[i].x - x0) <= 1e-10 && ab(sak[i].y) <= 1e-10) { bj = i; } } memset(f, -INF, sizeof (f)); f[1][bj][bj] = f[2][bj][bj] = 0.0; for (int k = 1;k <= n; ++k) { for (int i = 1;i + k <= n; ++i) { int j = i + k; f[1][i][j] = sak[i].y + max(f[1][i + 1][j] - (sak[i + 1].x - sak[i].x) * Sum(i + 1, j), f[2][i + 1][j] - (sak[j].x - sak[i].x) * Sum(i + 1, j)); f[2][i][j] = sak[j].y + max(f[1][i][j - 1] - (sak[j].x - sak[i].x) * Sum(i, j - 1), f[2][i][j -1] - (sak[j].x - sak[j - 1].x) * Sum(i, j - 1)); } } printf("%.3lf", max(f[1][1][n], f[2][1][n]) / 1000.0); return 0; }

后来听人说这是未来DP???

posted @   SilentEAG  阅读(192)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
CONTENTS