标签:10180 LibreOJ min 队列 int hh 单调 DP
题目来源
反思
因为目前在学习单调队列优化DP,所以会往单调队列上面想。然后犯了一个错误就是,认为这个题目只要用单调队列就可以完成,单调队列只是用来减少时间复杂度的,遇到了求最优解的题目,最先要想到的还是贪心和DP。
题解
- 分析题目
n 个烽火台,连续m个烽火台至少要有一个发出信号,每个烽火台具有代价,求最小的总代价。
求最值,想到DP、贪心。DP可以往前一个状态想,似乎可以由前一个状态转移过来,尝试使用DP去AC这题。
- DP分析
状态表示:
f
(
i
)
f(i)
f(i)表示选第
i
i
i个物品所有情况代价。
属性:
m
i
n
min
min
状态划分:要往前一个方向上想,那么就是:从前m个数中选,一个代价最小的数,加上当前代价。
方程为:
f
(
i
)
=
m
i
n
(
f
(
j
)
)
+
w
(
i
)
f(i) = min(f(j)) + w(i)
f(i)=min(f(j))+w(i) _____
j
∈
[
i
−
m
+
1
,
i
]
j \in [i - m + 1, i]
j∈[i−m+1,i]
那么
f
(
j
)
f(j)
f(j)就可以使用单调队列去优化时间复杂度。
单调队列的性质为单调递增,我们想要的值在队首。
接下就看代码即可。1
AC 代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rep(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << endl
#define mod(x) (x) % MOD
#define ENDL "\n"
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 2e5 + 7, MOD = 1e9, INF = 0x3f3f3f3f;
int q[N], w[N], f[N];
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cout.tie(0), cin.tie(0);
int n, m;
cin >> n >> m;
_for(i, 1, n) cin >> w[i];
int hh = 0, tt = 0, ans = INF;
_for(i, 1, n) {
if (hh <= tt && i > q[hh] + m) ++hh;
f[i] = f[q[hh]] + w[i];
while (hh <= tt && f[i] <= f[q[tt]]) --tt;
q[++tt] = i;
if (i > n - m) ans = min(ans, f[i]);
}
cout << ans << ENDL;
return 0;
}
代码中有一个细节,就是进入循环的时候队列并不为空,而是入队了一个0进入,目的就是为了初始化 f f f的前m个元素,防止多加一次代价。 ↩︎
标签:10180,LibreOJ,min,队列,int,hh,单调,DP 来源: https://blog.csdn.net/qq_46276931/article/details/117922879
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。