Description
给出一长度为len的序列和一整数t,构成一长度为len*t的序列满足a[i]=a[i-len](len < i <=len*t),要求输出这个长串的最长非严格上升子序列长度
Input
第一行为两个整数len和t,第二行len个整数ai表示这个序列(1<=len<=100,1<=t<=10^7,1<=ai<=300)
Output
输出将输入序列重复t次之后的序列的最长非严格上升子序列长度
Sample Input
4 3
3 1 4 2
Sample Output
5
Solution
暴力求整个串的LIS显然超时,分析一下整个序列的LIS组成,由于整个序列是有t个长度不超过len的序列组成,那么LIS中不同数的数量不会超过len,即序列中应该有一部分是连续相同的,只要我们求出len*len长度的序列的LIS,再找出len序列中出现次数最多的数插在LIS相应位置即为整个序列的LIS
Code
#include<stdio.h>
#include<string.h>
#define maxn 100*100+1
#define INF 1<<29
int len,t,a[maxn],cnt[301];
int dp[maxn],n;
int get_upper_bound(int x)
{
int l=0,r=n-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(dp[mid]>x)
r=mid-1;
else
l=mid+1;
}
return l;
}
int LIS(int a[])
{
for(int i=1;i<n;i++)
dp[i]=INF;
dp[0]=a[0];
int len=1;
for(int i=1;i<n;i++)
{
if(a[i]>=dp[len-1])
dp[len++]=a[i];
else
dp[get_upper_bound(a[i])]=a[i];
}
return len;
}
int main()
{
while(~scanf("%d%d",&len,&t))
{
memset(cnt,0,sizeof(cnt));
for(int i=0;i<len;i++)
{
scanf("%d",&a[i]);
cnt[a[i]]++;//痛就序列中每种数字出现次数
}
int max=0;
for(int i=0;i<=300;i++)//找到序列中数字最大出现次数
max=max<cnt[i]?cnt[i]:max;
n=len*(len>t?t:len);
for(int i=len;i<n;i++)
a[i]=a[i-len];
int ans=LIS(a);//求出min(t,len)*len的LIS
ans+=(t>len?t-len:0)*max;//将出现最多的数字插入到LIS中构成整个串的LIS
printf("%d\n",ans);
}
return 0;
}