题目
Description
烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在 某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。
Input
第一行:两个整数 N,M。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。
Output
一行,表示答案。
5 3
1 2 5 6 2
4
Data Constraint |
对于50%的数据,M≤N≤1,000 。 对于100%的数据, |
M≤N≤100,000,Wi≤100。 |
分析
这道很明显,如果用DP做一定超时,所以我们用单调队列优化
那该怎么优化法呢
首先我们分析状态转移方程 f[j]=min(f[j],f[k]+a[i])
如果做的是循环k 然后直接枚举. o(n^2)
显然这肯定超时
所以我们就这样做:
构造一个递增单调队列,所以最小的值一定在队头
用单调队列来代表f里面的值的
这样就可以省下k这个循环了
但是最后的答案是在i=n-m i<=n 里
代码
1 #include<iostream> 2 #define N 100000 3 using namespace std; 4 int a[N+1]; 5 int f[N+1],que[N+1]; 6 int main () 7 { 8 int n,m; 9 cin>>n>>m; 10 for (int i=1;i<=n;i++) 11 cin>>a[i]; 12 int h=1,t=1; 13 for (int i=1;i<=n;i++) 14 { 15 while (h<=t&&f[i-1]<=f[que[t]]) t--; //如果当前插入的值比队尾小就要插队 16 que[++t]=i-1; 17 while (h<=t&&que[h]+m<i) h++; //如果超出范围就要头指针后移 18 f[i]=f[que[h]]+a[i]; //结果就是当前队列最小值加上当前a了 19 } 20 int ans=1e9; 21 for (int i=n;i>n-m;i--) 22 ans=min(ans,f[i]); 23 cout<<ans; 24 }