[codeforces]1223F Stack Exterminable Arrays

这是一篇关于Codeforces 1223F题目的博客,讨论如何在O(N)时间内计算可灭绝数组nxt,通过巧妙的数据结构和算法设计,避免了O(N^2)的复杂度,主要涉及动态规划和数组处理技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很巧妙的一道题
首先我们考虑计算nxt数组,表示从第 i i i个位置起第一个下标 r r r使得 a l . . r a_{l..r} al..r为可灭绝的,只要求出nxt[i]我们就可以使用DP在 O ( N ) O(N) O(N)时间内求出答案。
考虑计算nxt[i]数组的方法,如果直接计算总复杂度是 O ( N 2 ) O(N^2) O(N2)的,我们要寻找在 O ( N ) O(N) O(N)时间内求出这个数组的方法。
添加一个map nxtX[i][j],表示第一个下标 r + 1 r + 1 r1使得 a l . . . r a_{l...r} al...r为可灭绝的并且 a r + 1 = j a_{r+1}=j ar+1=j,由nxtX[i]我们可以轻易求出nxt[i], n x t [ i ] = n x t X [ i + 1 ] [ a [ i ] ] nxt[i]=nxtX[i+1][a[i]] nxt[i]=nxtX[i+1][a[i]],nxtX怎么求呢?
假设我们已经更新完nxt[i],我们可以让 n x t X [ i ] = n x t X [ n x t [ i ] + 1 ] nxtX[i]=nxtX[nxt[i]+1] nxtX[i]=nxtX[nxt[i]+1],然后让 n x t X [ i ] [ a n x t [ i ] + 1 ] = n x t [ i ] + 1 nxtX[i][a_{nxt[i]+1}]=nxt[i]+1 nxtX[i][anxt[i]+1]=nxt[i]+1。每次循环结束后把自己更新一下 n x t [ i ] [ a [ i ] ] = i nxt[i][a[i]]=i nxt[i][a[i]]=i
需要注意的是,对于这个map数组,如果直接赋值的话是可以卡到 O ( N 2 ) O(N^2) O(N2)的,所以需要swap。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>

using namespace std;
const int  N = 300010;
int nxt[N], a[N], dp[N];
map<int, int> nxtX[N];
int main()
{
    int n, T;
    cin>>T;
    while(T--){
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for (int i = 1; i < n + 3; ++i){
            nxt[i] = -1;
            nxtX[i].clear();
            dp[i] = 0;
        }
        for (int i = n; i; --i){
            if (nxtX[i + 1].count(a[i])){
                int pos = nxtX[i + 1][a[i]];
                if (pos <= n && a[pos] == a[i]){
                    nxt[i] = pos;
                    swap(nxtX[i], nxtX[nxt[i] + 1]);
                    if (pos < n) nxtX[i][a[pos + 1]] = pos + 1; 
                }
            }
            nxtX[i][a[i]] = i;
        }
        long long ans = 0;
        for (int i = n; i; i--){
            if (nxt[i] == -1) continue; 
            dp[i] = dp[nxt[i] + 1] + 1;
            ans += dp[i];
        }
        printf("%lld\n", ans);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值