1. 程式人生 > >【單調佇列DP】烽火傳遞

【單調佇列DP】烽火傳遞

**

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;
}