[codeforces]1223F Stack Exterminable Arrays

很巧妙的一道题
首先我们考虑计算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
#include
#include
#include
#include
#include

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);
    }
}

你可能感兴趣的:(动态规划)