测温(dp+双端队列)

测温

[Link](测温 - 题目 - Daimayuan Online Judge)

题意

​ 某国进行了连续 n n n天的温度测量,测量存在误差,测量结果是第 i i i天温度在 [ l i , r i ] [l_i,r_i] [li,ri]范围内。求温度不下降的最长连续天数。

思路

​ 考虑 f [ i ] [ j ] : 第 i 天 温 度 为 j 的 最 大 值 f[i][j]:第i天温度为j的最大值 f[i][j]:ij,那么 f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] + 1 )   k ≤ j f[i][j]=max(f[i-1][k]+1) \ k\le j f[i][j]=max(f[i1][k]+1) kj,这样 d p dp dp复杂度是 O ( n w ) O(nw) O(nw)还是无法接受的,观察一下 f [ i ] f[i] f[i]的性质发现他是单调的即 f [ i ] [ j + 1 ] ≥ f [ i ] [ j ] f[i][j +1]\ge f[i][j] f[i][j+1]f[i][j](温度高的一定可以接到温度低的接到的地,要不就是接到一个更优的前面)。

​ 因此 f [ i ] [ j ] f[i][j] f[i][j]的值一定是一段一段且非递减的例如 f [ i ] [ 1 ∼ 3 ] = 4 , f [ i ] [ 4 ∼ 6 ] = 5 , f [ i ] [ 7 ∼ 10 ] = 6 f[i][1\sim 3] =4,f[i][4\sim6]=5,f[i][7\sim10] = 6 f[i][13]=4,f[i][46]=5,f[i][710]=6,因此我们可以维护上一个状态的区间而不是维护具体的点,这个可以用一个 d e q u e deque deque来搞,对于新的状态的区间 [ l i + 1 , r i + 1 ] [l_{i+1},r_{i+1}] [li+1,ri+1]就从前一个状态合法的区间转移过来即可。

​ 例如 [ l i + 1 , r i + 1 ] [l_{i+1},r_{i+1}] [li+1,ri+1] [ 5 , 8 ] [5, 8] [5,8],我们的思路是:

​ 首先如果新的区间左端点比维护的左端点更小就加入多的这一段且权值为 1 1 1

​ 如果右端点比维护右端点更大,我们就把维护右端点置成新区间的 r r r,因为这个 r r r更大所以一定可以接到前一个区间的最右面后面(就是转移时合法的)

​ 然后如果最左边的区间的右端点小于我们的新区间的 l l l,我们就把它弹出去(即不合法无法转移)

​ 同理最右边的区间的左端点如果大于我们新区间的 r r r,也弹出去。

转移过来的区间都要加上 1 1 1,对于区间加我们可以维护一个 t a g tag tag表示这个区间加了多少次,对于左边那个新加入的区间我们让他等于 − t a g -tag tag相当于减去了偏移量,每次和我们维护的 d e q u e deque deque的右端更新一下答案即可(非递减的因此只看有段即可)。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int tag;
int a[N];
struct Node {
    int l, r, c;
};
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n;
    int res = 1;
    deque<Node> q;
    for (int i = 1; i <= n; i ++) {
        int l, r; cin >> l >> r;
        if (q.size() && q.front().l <= r) {
            while (q.size() && q.back().l > r) q.pop_back();
            if (q.size()) q.back().r = r;
            if (l < q.front().l) q.push_front({l, q.front().l - 1, -tag});
            while (q.size() && q.front().r < l) q.pop_front();
            if (q.size()) q.front().l = max(q.front().l, l);
            tag ++;
        }
        else {
            q.clear();
            q.push_back({l, r, 1});
            tag = 0;
        }
        res = max(res, q.back().c + tag);
    }

    cout << res << '\n';
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值