noip2010烽火传递
问题背景
(NOIP2010 初赛)
题目描述
烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情。在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确的传递,在m个烽火台中至少要有一个发出信号。现输入n、m和每个烽火台发出的信号的代价,请计算总共最少需要话费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递!!!
输入格式
第一行有两个数n,m分别表示n个烽火台,在m个烽火台中至少要有一个发出信号。
第二行为n个数,表示每一个烽火台的代价。
输出格式
一个数,即最小代价。
样例输入1
5 3
1
2
5
6
2
样例输出1
4
注释说明
对于50%的数据,M≤N≤1,000 。 对于100%的数据,M≤N≤ 100,000,Wi≤100。
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],f[100005];
deque<int>q;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int k=1;k<=m;k++){
f[k]=a[k];
}
for(int i=m+1;i<=n;i++){
int d=0x7f7f7f7f;
for(int j=i-m;j<=i-1;j++){
d=min(d,f[j]);
}
f[i]=d+a[i];
}int ans=0x7f7f7f7f;
for(int i=n-m+1;i<=n;i++){
ans=min(ans,f[i]);
}
printf("%d",ans);
}
/*
5 3
1
2
5
6
2
*/
单调队列优化
首先申请一个双端队列q:
deque<int> q;
该元素过期(i-m>q.front()),队首元素就要出队。
if i<=m f[i]=a[i];
else f[i]=f[q.front()]+a[i];
当队列非空,并且当前元素a[p]比队尾元素小,那么队尾元素就要出队;
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],f[100005],p=0x7f7f7f7f;
deque<int>q;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
while(!q.empty()&&i-m>q.front()){
q.pop_front();
}
if(i<=m){
f[i]=a[i];
}
else {
f[i]=f[q.front()]+a[i];
}
while(!q.empty()&&f[i]<=f[q.back()]){
q.pop_back();
}
q.push_back(i);
}
int ans=p;
for(int i=n-m+1;i<=n;i++){
ans=min(ans,f[i]);
}
printf("%d",ans);
}
/*
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],f[100005];
deque<int>q;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int k=1;k<=m;k++){
f[k]=a[k];
}
for(int i=m+1;i<=n;i++){
int d=0x7f7f7f7f;
for(int j=i-m;j<=i-1;j++){
d=min(d,f[j]);
}
f[i]=d+a[i];
}int ans=0x7f7f7f7f;
for(int i=n-m+1;i<=n;i++){
ans=min(ans,f[i]);
}
printf("%d",ans);
}
5 3
1
2
5
6
2
*/
*****撒花*****