描述
烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情。在某两座城市之间有
n
个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确的传递,在
输入格式
第一行有两个数
n,m
分别表示
n
个烽火台,在
第二行为
n
个数,表示每一个烽火台的代价。
输出格式
一个数,即最小代价。
测试样例1
输入
5 3
1 2 5 6 2
输出
4
备注
solution
首先转换一下问题,该问题可以转换成在所给的序列中选几个数,相邻的数字位置差 ≤m ,并且和最小
令 f[i] 表示只考虑 1−i ,第 i 个数字被选出的最小和
那状态转移方程显然是
f[i]=w[i]+min{f[j]} ,其中 j−i 的距离 ≤m ,即 i−m≤j≤i−1考虑 f[i+1] ,转移的时候 j 的范围是
i−m+1≤j≤i 我们把这两个范围在数轴上表示一下
- 不难看出仅仅是在后面删除了一个数 i−m ,前面新加入了 i <script type="math/tex" id="MathJax-Element-21">i</script> ,这样就可以用单调队列来优化了
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
template<typename T>
void input(T &x) {
x=0; T a=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') a=-1;
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
x*=a;
return;
}
#define MAXN 1000010
int w[MAXN];
int f[MAXN];
int q[MAXN];
int head,tail;
int main() {
int n,m;
input(n),input(m);
for(int i=1;i<=n;i++)
input(w[i]);
for(int i=1;i<=n;i++) {
while(head<=tail&&f[q[tail]]>=f[i-1])
tail--;
q[++tail]=i-1;
while(q[head]<i-m) head++;
f[i]=w[i]+f[q[head]];
}
int ans=2147483647;
for(int i=n;i>n-m;i--)
ans=min(ans,f[i]);
printf("%d\n",ans);
return 0;
}