代码源 div1每日一题 #507.测温

测温

这道题好独特,本来以为是贪心+单调栈之类的。。后来想了下发现有个信息完全不知道怎么维护,下面是整理dls的思路。

考虑一个比较暴力的方法, d p [ i ] [ j ] dp[i][j] dp[i][j]为考虑到第i天,当前温度为j时,连续的最长天数,所以我们有这样的转移
d p [ i ] [ j ] = d p [ i − 1 ] [ k ] + 1 , k < = j dp[i][j] = dp[i - 1][k]+1, k <= j dp[i][j]=dp[i1][k]+1,k<=j
这个dp的时间复杂度为 O ( n ∗ W ) O(n*W) O(nW)

再仔细观察,发现这样一件事情:如果若 j > = k j >= k j>=k,有 d p [ i ] [ j ] > = d p [ i ] [ k ] dp[i][j] >= dp[i][k] dp[i][j]>=dp[i][k],因为小的满足,大的肯定也满足。

so?有了上面的性质,就知道 d p [ i ] [ j ] dp[i][j] dp[i][j]里面肯定是维护了一堆连续单调的数字,且包含这些值这些区间都是连续的

所以我们可以把第二维去掉,用一个队列来维护这些离散的区间!

d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j]维护的r要大于当前的r时,我们把多余的部分弹出这个区间

情况1:
dp[i - 1][j],        l1-------------- r1
l[i], r[i]    l2---------r2

dp[i][j]变成这样
		      l2-----l1--r2
		      
情况2
dp[i - 1][j],        l1-------------- r1
l[i], r[i]                      l2---------r2

dp[i][j]变成这样
		                        l2-----r1--r2

对于能由上一个转移来的区间,直接+1,多余部分弹出队列,而新增的部分,直接为1即可。这一部分用一个双端队列维护即可

如果可以转移,那么这意味对队列里面的一些小区间都+1,对于队列里面区间的val都加1的这个操作,我们可以维护一个全局加的数字S,每次我们加入一个新的值时,需要减去这个全局偏移(我也是对拍搞了很久才找到这个bug)。真实值为val+S

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1e6 + 10, M = N + N, P = 131, INF = 1e9 + 10;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
using tp = tuple<int,int,int>;
bool muti = false;
int n, m;

struct Range
{
    int l, r, val;
};

void solve() {
    scanf("%d", &n);
    deque<Range> q;
    int S = 0;              //全局偏移
    int res = 0;
    for(int i = 0; i < n; i++) {
        int l, r;
        scanf("%d%d", &l, &r);
        //可以继承i-1的情况
        if(q.size() && r >= q.front().l) {
            //先弹出无法转移的
            while(q.size() && q.back().l > r) q.pop_back();
            //最后一段满足的设置为r, 最后一段的r设置为r
            if(q.size()) q.back().r = r;
            
            //处理左半的区间
            if(q.front().l > l) {
            	//特别注意这里的值是 0-S = -S
                q.push_front({l, q.front().l - 1, -S});
            }
            else {
                while(q.size() && q.front().r < l) q.pop_front();
                if(q.front().l < l) q.front().l = l;
            }
            S++;
        }
        else {
            q.clear();
            q.push_back({l, r, 1});
            S = 0;
        }
        res = max(res, q.back().val + S);
    }
    cout << res << endl;
    
}


int main()
{
#ifdef ONLINE_JUDGE
#else 
    freopen("E.txt", "r", stdin);
#endif
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int T = 1;
    if(muti) cin >> T;
    while (T--) solve();
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值