嘘~ 正在从服务器偷取页面 . . .

LOJ10180 「一本通 5.5 练习 1」烽火传递 题解


LOJ10180 「一本通 5.5 练习 1」烽火传递 题解

题目链接:「一本通 5.5 练习 1」烽火传递

题意

原题来自:NOIP 2010 提高组初赛 · 完善程序

烽火台是重要的军事防御设施,一般建在交通要道或险要处。一旦有军情发生,则白天用浓烟,晚上有火光传递军情。

在某两个城市之间有 $n$ 座烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确传递,在连续 $m$ 个烽火台中至少要有一个发出信号。现在输入 $n,m$ 和每个烽火台的代价,请计算总共最少的代价在两城市之间来准确传递情报。

输入格式

第一行是 $n,m$,表示 $n$ 个烽火台和连续烽火台数 $m$;

第二行 $n$ 个整数表示每个烽火台的代价 $a_i$。

输出格式

输出仅一个整数,表示最小代价。

记得哪次模拟赛考过一题,在区间中选不相连的若干段且每段长度都不超过 $m-1$ ,求最大的和。

这题实际上就是反过来的,而且还有两个城市需要连起来。

首先我们在序列左右各放一个花费为 $0$ 的烽火台,然后设 $f_i$ 为 $i$ 必选时的最小花费。

$f$ 的初值为 $+\infty$ ,除了 $f_0=0$ 。转移很简单

这个显然可以用单调队列优化,最后答案就是 $f_{n+1}$ 。

时间复杂度 $\mathcal{O}(n)$

代码:(我单调队列的写法是 (st,en] 的)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(2e5 + 15))

int n, m, st, en, S, a[N], q[N], dp[N];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m; q[en = 1] = st = 0;
    memset(dp, 0x3f, sizeof(dp)); dp[0] = 0;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n + 1; i++)
    {
        while(st < en && i - q[st + 1] > m) ++st;
        dp[i] = dp[q[st + 1]] + a[i];
        while(st < en && dp[q[en]] > dp[i]) --en;
        q[++en] = i;
    }
    cout << dp[n + 1] << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录