AtCoder Beginner Contest 247 E 双指针维护固定最大最小值区间的数量 状压DP

题目

给你一个大小为n的数组A,以及一个X和Y。
要求求出满足最大值为X且最小值为Y的区间数量。
数据范围
在这里插入图片描述

题解思路

很久没写双指针题了,有点不太行,所以一直没自己补出来,一开始看的dls的状压dp
dp[i][0/1][0/1] 定义为以i为右端点的连续区间中 有或者没有最小值Y
有或者没有最大值X的数量。
再通过此时的a[i]值来更新到这个点的数量。
每次取dp[i][1][1]即可。
梦中把这题用双指针补了。
结果思路真是对的,官方题解也讲了双指针,可惜我看不懂英文。
所以才只能自己推。
我们只需维护双指针的区间中具有几个XY以及从i点能取的区间的 最小右端点以及左端点 且保证区间中的数都是在范围里面的。
当i为X或者Y的时候,我们需要对应的更新区间的XY数量,以及能取的最小右端点,我们得预处理出每个XY对应的下个XY,当这个点被删除了我们只能取下个点对之前的点取max。

AC代码

双指针写法

#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define int long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  1000100;
int a[N] ; 
void solve()
{
    int n , x , y ;
    cin >> n >> x >> y ; 
    long long ans = 0 ; 
    for (int i = 1 ; i <= n ; i++ )
        cin >> a[i] ;
    map <int , int > mp ; 
    int lastx = 0 ; 
    for (int i = 1 ; i <= n ; i++ )
    {
        if (a[i] == x )
        {
            if (!lastx)
                lastx = i ; 
            else
            {
                mp[lastx] = i ; 
                lastx = i ; 
            }
        }
    }
    lastx = 0 ; 
    for (int i = 1 ; i <= n ; i++ )
    {
        if (a[i] == y )
        {
            if (!lastx)
                lastx = i ; 
            else
            {
                mp[lastx] = i ; 
                lastx = i ; 
            }
        }
    }
    int mac = 0 , mic = 0 , spj = 0 ;
    for (int i = 1 , j = 1 ; i <= n ; i++ )
    {
        if ( a[i] > x || a[i] < y )
        {
            mac = 0 , mic = 0 , spj = 0 ; 
            continue;
        }
        if ( i > j )
            j = i ; 
        while ( j <= n )
        {
            if (a[j] > x || a[j] < y )
                break;
            if (a[j] == x )
                mac++;
            if (a[j] == y )
                mic++;
            if (spj == 0 && mac && mic )
                spj = j ; 
            j++;
        }
        if (spj != 0 && mac && mic)
        {
            ans += j - spj ;
            //cout << i << " " << spj << " " << j << "\n" ; 
        }
        if (a[i] == x )
            mac--, spj = max(mp[i],spj) ;
        if (a[i] == y )
            mic--, spj = max(mp[i],spj)  ;
        if ( spj >= j )
            spj = 0 ; 
        //cout << mac << " " << mic << " " << spj << "\n" ; 
        if (mac == 0 || mic == 0 )
            spj = 0 ; 
    }
    cout << ans << "\n" ; 
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        solve() ;
    return 0 ;
}

DP写法

#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  200100;
int a[N] ; 
long long dp[N][3][3] ; 

void solve()
{
    int n ;
    int x , y ; 
    cin >> n >> x >> y ;
    for (int i = 1 ; i <= n ; i++ )
        cin >> a[i] ; 
    long long ans = 0 ; 
    for (int i = 1 ; i <= n ; i++ )
    {
        if (a[i] < y || a[i] > x )
            continue;
        int fs = a[i] == x , ft = a[i]==y ; 
        dp[i][fs][ft] += 1 ; 
        for (int j = 0 ; j < 2 ; j++ )
            for (int k = 0 ; k < 2 ; k++ )
                dp[i][j|fs][k|ft] += dp[i-1][j][k] ;
        ans += dp[i][1][1] ; 
    }
    cout << ans << "\n" ; 
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        solve() ;
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值