題目:p3800 power收集
單調佇列 - dp
考慮 f[i
][j]
f[i][j]
f[i][j
] 表示走到位置(i,
j)
(i,j)
(i,j
)時可以獲得的最大權值
我們發現 f[i
][j]
f[i][j]
f[i][j
] 是由 f[i
][j−
k]∼f
[i][
j+k]
f[i][j-k] \sim f[i][j+k]
f[i][j
−k]∼
f[i]
[j+k
] 和 f[i
−1][
j]
f[i-1][j]
f[i−1]
[j] 轉移過來的
那麼,我們可以用單調佇列維護區間 [j−
k,j+
k]
[j-k,j+k]
[j−k,j
+k] 內 f
ff 的最大值
明白這個後就很簡單了,維護單調遞減佇列並列舉更新就可以了
注意有一點很容易錯:在同一行你只能瞬移一次,並且不能折返
也就是說瞬移的上一步不能還是瞬移,所以要用乙個輔助陣列s
ss
for
(int i=
1;i<=n;
++i)
q.clear()
;for
(int j=
1;j<=k;
++j)
push
(i,j)
;for
(int j=
1;j<=m;
++j)
for(
int j=
1;j<=m;
++j)
f[i]
[j]=
max(f[i]
[j],s[j]);
// 最後合併取最大值
}
完整**:
#include
#include
#include
#include
using
namespace std;
const
int maxn=
4010
,inf=
0x3f3f3f3f
;int f[maxn]
[maxn]
,a[maxn]
[maxn]
;int s[maxn]
;int n,m,k,ans;
deque <
int> q;
inline
intread()
while
(ch>=
'0'&& ch<=
'9')s=
(s<<3)
+(s<<1)
+(ch^48)
,ch=
getchar()
;return s*w;
}void
push
(int i,
int j)
q.push_back
(j);
}void
pop(
int x)
}int
main()
for(
int i=
1;i<=n;
++i)
q.clear()
;for
(int j=
1;j<=k;
++j)
push
(i,j)
;for
(int j=
1;j<=m;
++j)
for(
int j=
1;j<=m;
++j)
f[i]
[j]=
max(f[i]
[j],s[j]);
}for
(int i=
1;i<=m;
++i)
ans=
max(ans,f[n]
[i])
;printf
("%d\n"
,ans)
;return0;
}
洛谷p3800power收集
原題 一道很不錯的優先佇列題 f i j 的最大值由上一行的狀態有關,轉移方程f i j max f i 1 z a i j z j k,j k 每個轉移會超時,所以我們對上一行建立單調佇列,由1推到m,提前入隊,超出範圍出隊。include include include include incl...
洛谷P3800 Power收集
顯然這是一道dp題,樸素演算法很容易想 dp i j v i j max dp i 1 k j t leq k leq j t 然而這樣的轉移是 o nm 2 的,不合要求,還要繼續優化。注意到 k leq 4000 棋盤的資料是相當稀疏的,那麼我們考慮將有p點的格仔當成乙個結點,建圖。根據題意 必...
洛谷 P3800 Power收集
據說在紅霧異變時,博麗靈夢單身前往紅魔館,用十分強硬的手段將事件解決了。然而當時靈夢在power達到max之前,不具有 上線收點 的能力,所以她想要知道她能收集多少p點,然而這個問題她答不上來,於是她找到了學oi的你。可以把遊戲介面理解成乙個n行m列的棋盤,有k個格仔上有p點,其價值為val i,j...