P1886 滑动窗口 /【模板】单调队列
题目思路:单调队列模版题,每次都输出队列中的第一个元素。以此维护队列中元素序号的单调性,得到结果。只是比较判断,时间复杂度很小。相等的值也要挤掉。最大值同理。
代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 3000005
ll dp[N], f1[N], f2[N];
ll a[N], b[N], c[N];
bool vis[N], flag;
ll x, y, z, n, m, t, k;
ll ans, sum, cnt;
deque<ll>q;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
while (!q.empty() && a[q.back()] >= a[i]) q.pop_back();
q.push_back(i);
if (i >= m) {
while (q.front() <= i - m) q.pop_front();
cout << a[q.front()] << " ";
}
}
cout << endl;
q.clear();
for (int i = 1; i <= n; i++) {
while (!q.empty() && a[q.back()] <= a[i]) q.pop_back();
q.push_back(i);
if (i >= m) {
while (q.front() <= i - m) q.pop_front();
cout << a[q.front()] << " ";
}
}
return 0;
}
P1901 发射站
题目思路: 用一个线性算法,先从左往右推。若在栈中栈顶那个塔的高度比当前塔的高度低,即此塔为栈顶塔右边的第一个比栈顶塔高的塔,那么栈顶塔的能量就要加给当前塔,然后将队列顶塔出栈。直到队列内无塔或下一塔比它的高度高,就将该塔进队列,并指向下一个塔。反之亦然。两趟之间要清空栈,最后再打个擂台,找MAX。
代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 3000005
ll dp[N], f1[N], f2[N];
ll a[N], b[N], c[N];
bool vis[N], flag;
ll x, y, z, n, m, t, k;
ll ans, sum, cnt;
deque<ll>q;
struct node {
ll x, y, z;
}f[N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> f[i].x >> f[i].y;
for (int i = 1; i <= n; i++) {
while (!q.empty() && f[q.back()].x < f[i].x) {
f[i].z += f[q.back()].y;
q.pop_back();
}
if (!q.empty()) {
f[q.back()].z += f[i].y;
}
q.push_back(i);
}
for (int i = 1; i <= n; i++)
ans = max(ans, f[i].z);
cout << ans << endl;
return 0;
}
P1419 寻找段落
题目思路:
首先看出答案满足单调性,可以二分答案,转化为判定性问题。令最优平均值为k,对于所有合法序列[l..r],尝试将分式变为整式:s[l..r]>k*(r-l+1)无解。移项,令b[i]=a[i]-k,s’[i]为b[1]..b[n]的和,则有寻找长度在[s,t]内的子段和的最大值可以用单调队列解决
代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 3000005
ll dp[N], f1[N], f2[N], a[N];
double b[N], c[N];
bool vis[N], flag;
ll x, y, z, n, m, t, k;
ll sum, cnt;
double l, r, mid, ans;
deque<ll>q;
bool check(double k) {
q.clear();
for (int i = 1; i <= n; i++)
c[i] = (double)a[i] - k;
for (int i = 1; i <= n; i++) {
b[i] = b[i - 1] + c[i];
}
for (int i = 1; i <= n; i++) {
if (i >= x) {
while (!q.empty() && b[q.back()] > b[i - x]) q.pop_back();
q.push_back(i - x);
}
if (!q.empty() && i - y > q.front()) q.pop_front();
if (!q.empty() && b[i] - b[q.front()] >= 0) return true;
}
return false;
}
int main()
{
cin >> n >> x >> y;
for (int i = 1; i <= n; i++)
cin >> a[i];
l = -10000; r = 10000;
while (r - l > 1e-5) {
mid = (l + r) /2;
if (check(mid))
ans = l = mid;
else
r = mid;
}
printf("%.3lf\n", ans);
return 0;
}