题目链接:
题目大意:
给出一个序列,是由一个长度为n的序列复制T次得到的,问最长子序列的长度。
题目分析:
- 我们可以暴力的做n*n内的部分,得到这部分的最长不降子序列。
- 我们可以知道如果通过选取递减的可以得到更好的结果,那么在这之中一定已经选过,就算每次下降都能得到更好的结果,那么n次下降也能保证后面添加的全部都是只加入相同的元素,所以我们找到出现次数最多的元素,然后加入这个元素即可,可以选择中间插入或者其他插入,因为对于每个值下降的操作只能做一次,所以这些相同的元素我们可以插在合适的位置。
- 仔细想一想就能明白,其实下降的位置因为相等的情况的插入后调并不会影响结果的最优性
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAX 10007
using namespace std;
int dp[MAX];
int s[MAX];
int a[MAX];
int cnt[307];
int n,t,ans;
int main ( )
{
while ( ~scanf ( "%d%d" , &n , &t ) )
{
memset ( cnt , 0 , sizeof ( cnt ) );
for ( int i = 1 ; i <= n ; i++ )
{
scanf ( "%d" , &a[i] );
cnt[a[i]]++;
}
int total = min(t,n)*n;
for ( int i = n+1 ; i <= total; i++ )
a[i] = a[i-n];
s[0] = 0;
int top = 0;
for ( int i = 1 ; i <= total; i++ )
{
int l=0,r=top,mid;
while ( l != r )
{
mid = (l+r+1)>>1;
if ( s[mid] <= a[i] ) l = mid;
else r = mid-1;
}
ans = max ( ans , l+1 );
if ( ans > top ) s[++top] = a[i];
else s[l+1] = min ( s[l+1] , a[i] );
}
int maxn = 0;
for ( int i = 1 ;i <= 300 ; i++ )
maxn = max ( maxn , cnt[i] );
ans += max ( t-n , 0 )*maxn;
printf ( "%d\n" , ans );
}
}