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

浙公网安备 33010602011771号