【單調佇列DP】烽火傳遞
阿新 • • 發佈:2018-12-11
**
1565 – 【堆練習】烽火傳遞3577
** Description 烽火臺是重要的軍事防禦設施,一般建在交通要道或險要處。一旦有軍情發生,則白天用濃煙,晚上有火光傳遞軍情。在某兩個城市之間有n(n<=200000)座烽火臺,每個烽火臺發出訊號都有一定的代價。為了使情報準確傳遞,在連續m個烽火臺中至少要有一個發出訊號。現在輸入n,m和每個烽火臺的代價(代價小於等於1000),請計算總共最少的代價在兩城市之間來準確傳遞情報。 Input 第一行是n,m表示n個烽火臺和連續烽火臺數m 第二行n個整數表示每個烽火臺的代價。 Output 輸出僅一個整數。 Sample Input 5 3 1 2 5 6 2 Sample Output 4
設f[i]表示從開始到第i個數字並且第i個數字必須選,滿足題 目條件的最小代價和。則: n F[i]=min{f[j]}+a[i],(i-m<=j<=i-1) n 求f[i]時: 要求區間{f[i-m],f[i-m+1],…,f[i-1]}中的最小值; n 求f[i+1]時:要求區間{f[i-m+1],…,f[i-1],f[i]}中的最小值; n 初始化:f[i]=a[i],(1<=i<=m) n Ans=min{f[i]},(n-m+1<=i<=n)
#include<iostream> #include<cstdio> using namespace std; const int maxn=200005; int n,m,f[maxn],a[maxn],q[maxn]; inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar(); return s*w; } int main() { int i,j,head=0,tail=0; n=read();m=read(); for(i=1;i<=n;i++)a[i]=read(); for(i=1;i<=m;i++) { f[i]=a[i]; while(tail>0&&a[i]<=a[q[tail]])tail--; q[++tail]=i; } for(i=m+1;i<=n;i++) { while(head<=tail&&q[head]<i-m)head++; f[i]=f[q[head]]+a[i]; while(head<=tail&&f[q[tail]]>=f[i])tail--; q[++tail]=i; } int ans=0x7fffffff/2; for(i=n-m+1;i<=n;i++)ans=min(ans,f[i]); cout<<ans; return 0; }