CF 2135A Against the Difference

A.Against the Difference


原题链接

题意简述

我们定义块是指数组中所有元素的长度都等于数组长度的数组。例如, \([3, 3, 3]\)\([1]\)\([4, 4, 4, 4]\) 是数块,而 \([1, 1, 1]\)\([2, 3, 3]\) 不是。
如果一个数组可以由任意数量的块(可能为零)连接而成,那么这个数组就被称为整齐数组。请注意,空数组总是整齐的。
给你一个由 \(n\) 个整数组成的数组 \(a\) 。求其最长整齐子序列 \(^{\text{∗}}\) 的长度。
\(^{\text{∗}}\) 序列 \(c\) 是序列 \(a\) 的子序列,如果 \(c\) 可以从 \(a\) 中任意删除几个(可能是零个或全部)元素。

解题思路

最长正数子序列考虑线性dp做法,注意到:
1.每个最长整齐子序列一定由多个小的最长整齐子序列组成
2.当且仅当当前枚举到的 \(a_i\) 出现次数大于等于 \(a_i\)时才能发生状态转移
3.转移时需要快速追踪 当前存在的 \(p_{a_i}\) 下标倒数第 \(a_i\)
我们可以定义一种 \(dp_i\),表示枚举到第 \(i\) 位时最长的最长整齐子数组
那么显然有 $dp_i= \max({dp_i,dp_k+a_i}) (k=p_{a_i}[|p_{a_i}|-a_i]-1) $
用stl内置 std::map或std::unordered_map 离散化记录下标后可以快速回答询问.

AC code

//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
void solve(){
    int n;cin>>n;
    vector<int>a(n+2);
    vector<int>cnt(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    vector<int>dp(n+1);
    unordered_map<int,vector<int>>mp;
    for(int i=1;i<=n;i++){
        cnt[a[i]]++;
        dp[i]=dp[i-1];
        mp[a[i]].push_back(i);
        if(cnt[a[i]]>=a[i]){
            int idx=(int)mp[a[i]].size()-a[i];
            int pre=mp[a[i]][idx];
            if(idx>=0&&i-a[i]+1>=pre) {
                dp[i]=max(dp[i],dp[max(pre-1,0)]+a[i]);
            }
        }
    }
    cout<<dp[n]<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    int T=1;cin>>T;
    while(T--) solve();
    return 0;
}
posted @ 2025-10-15 22:51  usedchang  阅读(23)  评论(0)    收藏  举报