You are given an array of positive integers a1, a2, ..., an × T of length n × T. We know that for any i > n it is true that ai = ai - n. Find the length of the longest non-decreasing sequence of the given array.
The first line contains two space-separated integers: n, T (1 ≤ n ≤ 100, 1 ≤ T ≤ 107). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 300).
Print a single number — the length of a sought sequence.
4 3 3 1 4 2
5
The array given in the sample looks like that: 3, 1, 4, 2, 3, 1, 4, 2, 3, 1, 4, 2. The elements in bold form the largest non-decreasing subsequence.
题意:给出一个初始的字符串,整个字符串是t个这样的字符串拼接。求出这样的非递减字符串的最大长度。
分析:t的上限是10的7次方,如果直接合并数组然后套LIS 模板的话肯定不行。所以这边可以分析,因为n的范围不大,在k不大于n的时候可以直接套LIS模板,当k的范围特别大的时候,由于整个大的数组是一片一片的,每一片都是初始输入的数组,将整个大的数组分成两个部分,一个是n个n数组求取最大非递减序列,另一个部分中间的数组选出的都是一个元素,插空拼接在整个大的数组中间。如例一:数组中出现的元素的个数都是1,最大个数的元素可以是2,最大子序列就是12234。实在不理解,可以将k的数据放小,找出规律即可。找出n数组中最大个数的元素,重复插空在中间。见AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
//map <int ,int> m;
const int maxn=10005;
int a[maxn],b[maxn],flag[305],dp[maxn];
int main()
{
int n,t;
while(~scanf("%d %d",&n,&t))
{
int k=1;
memset(flag,0,sizeof(flag));
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
flag[a[i]]++;
}
int nummax=0,num=0;
for(int i=1; i<=305; i++)
if(flag[i]>nummax)
{
nummax=flag[i]; //找到最多个数的数的个数
num=i;//找到最多个数的个数
}
for(int i=0; i<min(n,t); i++)
for(int j=1; j<=n; j++)
b[k++]=a[j];
dp[1]=b[1]; //模板
int maxlen=1;
for(int i=2; i<=k; i++)
{
int l=0;
int r=maxlen,mid;
if(dp[maxlen]<=b[i])//若此时最大长度的子序列的最小值 仍小于a[i] 则最大长度加一
dp[++maxlen]=b[i];
else
{
r=maxlen;
while(l<=r)
{
mid=(l+r)/2;
if(dp[mid]<=b[i])
l=mid+1;
else
r=mid-1;
}
//找到第一个大于a[i]的数 更新其的值 使其值更小
dp[l]=b[i];
}
}
// printf("num=%d nummax=%d\n",maxlen,nummax);
if(t > n) //在原来的基础上 将数目最多的数插空进去
maxlen += (t - n) * nummax;
printf("%d\n",maxlen);
}
}
刷题长见识……
特记下,以备后日回顾。