CodeForces 582 B.Once Again...(LIS)

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值