1. 程式人生 > >琪露諾(洛谷P1725)(簡單滑窗優化Dp)

琪露諾(洛谷P1725)(簡單滑窗優化Dp)

文章目錄

題目

非常廢話 傳送門

題目大意:

給你一個長度為n+1的格子,編號為[0,n],你在0,現在你要從0跳過n,每次你能跳到下一個格子的區間為[i+L,i+R],每個格子有一個價值A[i],求跳過n後使沿途格子價值和最大的最大值.

資料範圍

對於60%的資料:N<=10,000N <= 10,000 對於100%的資料:N<=200,000N <= 200,000 對於所有資料 1,000<=A[i]<=1,000-1,000 <= A[i] <= 1,000

]<=1,0001&lt;=L&lt;=R&lt;=N1 &lt;= L &lt;= R &lt;= N

思路

首先,我們可以非常容易地寫出: f[i]=max{f[j]}+a[i](max(iR,0)&lt;=j&lt;=iL)f[i]=max\{f[j]\}+a[i](max(i-R,0)&lt;=j&lt;=i-L) 但是這是一個O(n2)O(n^2)的Dp,對於這道題只能過部分分,於是我們就要往優化方面去想了。 我們發現,對於一個狀態f[i]的f[j]所處的區間[i-R,i-L],是隨我們i增大而不斷向右一移動的,那我們就可以利用這一性質來進行滑窗,我們視窗的寬度是固定的,用優先佇列儲存狀態時,只要頂部與i的距離大於(R-L+1)就說明無法轉移,彈出就是了 這樣之後複雜度就是O

(nlogn)O(nlog_n)

程式碼

#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std; int read(){ int f=1,x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } #define MAXN 200000 #define INF 0x3f3f3f3f struct node{ int p,val; friend bool operator < (node a,node b){return a.val<b.val;} }; int a[MAXN+5],f[MAXN+5]; priority_queue<node> Q; int main(){ int n=read(),L=read(),R=read(); for(int i=0;i<=n;i++) a[i]=read(); for(int i=L;i<=n;i++){ Q.push((node){i-L,f[i-L]}); while(Q.top().p<i-R) Q.pop(); f[i]=Q.top().val+a[i]; } int ans=-INF; for(int i=n+1-R;i<=n;i++) ans=max(ans,f[i]); printf("%d\n",ans); return 0; }