【简●解】[SDOI2008] Sue的小球
【簡●解】[SDOI2008] Sue的小球
計劃著刷\(DP\)題結果碰到了這樣一道論文題,幸好不是太難。
【題目大意】
口水話有點多,所以就直接放鏈接。傳送門
【分析】
看到題首先聯想到了曾經做過的關路燈。所以先按\(x\)值排序,然后進行區間\(DP\)。
不妨設\(f_1[i][j]\),\(f_2[i][j]\)分別表示從起點出發已射落\(i\)到\(j\)這一段彩蛋,當前停留在\(i\)點,\(j\)點的最大得分\(v\)。
考慮 \(f_1[i][j]\),即點\(i\)是當前射擊的彩蛋,射擊的得分與當前時刻掛鉤,但 是當前的時刻是不能從\(f_1[i][j]\)的狀態中表示出來的,我們進一步考慮 \(f_1[i][j]\)的求解。
由于射擊\(i\)的得分是\(y_i?t?v_i\),而\(t\)等于之前每一步決策移動的時間總和,這樣我們就可以把\(t?v_i\)?在之前的移動中就計算,也就是說每次移動都要把未來會減少的得分計算在內。 比如說從\(f_1[i+1][j]\)推到\(f_1[i][j]\),即從\(i+1\)走到\(i\)時除了\(i+1\)到\(j\)這一段彩蛋外,其它的彩蛋都在下落,將這丟失的分數一并計算到從\(i+1\)走到\(i\)中。由于\(-t*v_i\)已經在之前決策時計算,所以射擊時直接加上\(y_i\)即可。
所以可以先用\(sum[]\)計算\(v_i\)的前綴和,然后\(DP\)方程:
\[ f_1[i][j]=y[i]+max(f_1[i+1][j]+Sum(i+1,j)*(x_{i+1}-x_i),f_2[i+1][j]+Sum(i+1,j)*(x_j-x_i) \]
\[ f_2[i][j]=y[i]+max(f_1[i][j-1]+Sum(i,j-1)*(x_{j}-x_{i}),f_2[i][j-1]+Sum(i,j-1)*(x_j-x_{j-1}) \]
然后\(O(n^2)\)過。
【Code】
#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\)???
轉載于:https://www.cnblogs.com/silentEAG/p/10935723.html
總結
以上是生活随笔為你收集整理的【简●解】[SDOI2008] Sue的小球的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何以HTML显示Base64图像?
- 下一篇: guacamole 源码_guacamo