二次联通门 : cogs 920. [東方S1] 琪露诺
/* cogs 920. [東方S1] 琪露诺 dp 方程为dp[i] = max (dp[i - L], dp[i - L + 1] .... dp[i - R - 1], dp[i - R]); 要用单调队列优化 记录路径是只需像最短路问题一样记录前驱 后递归打印即可 */ #include <cstring> #include <cstdio> void read (int &now) { register char word = getchar (); bool temp = false; for (now = 0; word < '0' || word > '9'; word = getchar ()) if (word == '-') temp = true; for (; word >= '0' && word <= '9'; now = now * 10 + word - '0', word = getchar ()); if (temp) now = -now; } //#define Online #define INF 1e9 int N, L, R, Answer = -INF; int pos; #define Max 1000001 int dp[Max]; int Queue[Max]; int Head, Tail; int value[Max], pre[Max]; void Print_road (int now) { if (pre[now] != -1) Print_road (pre[now]); printf ("%d ", now); } int main (int argc, char *argv[]) { #ifdef Online freopen ("iceroad.in", "r", stdin); freopen ("iceroad.out", "w", stdout); #endif read (N); read (L); read (R); for (int i = 0; i <= N; i ++) read (value[i]); Tail = 1; memset (pre, -1, sizeof pre); for (register int i = L, res; i <= N; i ++) { if (i - L <= 0) continue; res = dp[i - L]; for (; Head <= Tail && (Queue[Head] + L > i || (Queue[Head] + R < i) || (Queue[Head] > i)); Head ++); for (; Head <= Tail && (res > dp[Queue[Tail]]); Tail --); Queue[++ Tail] = i - L; pre[i] = Queue[Head]; dp[i] = value[i] + dp[Queue[Head]]; if (Answer < dp[i]) { Answer = dp[i]; pos = i; } } printf ("%d ", Answer); Print_road (pos); printf ("-1"); return 0; }