题目
题解思路
一开始其实是想dp的,想了挺久的递推明明推对了又自我否定了。
然后想到了我们最后的序列肯定是类似两个两个相同的连接起来,我们要是把所有两个相同的两个端点变成一个区间。那这题岂不是队最大不相交区间数的问题了,直接排序贪心取即可。
动态规划也行的。
定义dp[i]为前i 个 数组成的合法子序列中 美观度的最大值
转移方程
dp[ i ] = max( dp[ i-1 ] , dp[ last[i] ] +1)
即可以从之前选择的这个数的最优情况来更新此时的最优
AC代码
贪心 + 最大不相交区间做法
#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 = 1000010;
int a[N] ;
struct node
{
int l , r ;
}s[N];
bool cmp (node A ,node B )
{
if ( A.r == B.r )
return A.l < B.l ;
return A.r < B.r ;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int cnt = 0 ;
int n ;
cin >> n ;
for (int i = 1 ; i <= n ; i++ )
cin >> a[i] ;
unordered_map <int , int > mp ;
for (int j = n ; j >= 1 ; j-- )
{
if (!mp[a[j]])
{
mp[a[j]] =j ;
}else
{
s[cnt] = {j , mp[a[j]]} ;
cnt++ ;
mp[a[j]] = j ;
}
}
sort(s,s+cnt,cmp);
int tp = 0 ;
int ans = 1 ;
for (int i = 0 ; i < cnt ; i++ )
{
if (s[i].l >= s[tp].r )
{
tp = i ;
ans ++ ;
}
}
cout << ans << "\n" ;
return 0 ;
}
动态规划写法
#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 = 1000010;
int a[N] ;
int last[N] ;
int dp[N] ;
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int cnt = 0 ;
int n ;
cin >> n ;
for (int i = 1 ; i <= n ; i++ )
cin >> a[i] ;
unordered_map <int , int > mp ;
for (int j = 1 ; j <= n ; j++ )
{
if (!mp[a[j]])
{
mp[a[j]] =j ;
}else
{
last[j] = mp[a[j]] ;
mp[a[j]] = j ;
}
}
/*for (int j = 1 ; j <= n ; j++ )
cout << last[j] << " " ;
cout << "\n" ; */
for (int i = 1 ; i <= n ; i++ )
{
if (last[i])
dp[i] = max(dp[i-1] , dp[last[i]] + 1 ) ;
else
dp[i] = dp[i-1] ;
//cout << dp[i] << " " ;
}
//cout << "\n" ;
cout << dp[n] << "\n" ;
return 0 ;
}