【LIS】【打地鼠】

打地鼠
【问题描述】
小A喜欢打地鼠!
一共有n只地鼠按照顺序出现,第i只地鼠的肥胖度为a[i]。每次⼩A可以打地
鼠,但是要保证之前没打过任何地鼠,或这只地鼠⽐之前的任何一只小A打过的地鼠都要肥。
当然题目没有这么简单。如果⼩A没有打完所有地鼠,那么剩下的地鼠将会再
次出现(来被小A打)。当然,地鼠不是傻⼦,如果自⼰出现了t次以后还没被打
死,那么就不会再出现了。
现在问,⼩A最多能打多少地鼠?
【输入文件】
输入文件为dishu.in。
第⼀⾏包含4个整数k n max t。分别表示数据组数,地鼠个数,a[i]的最大值,
每个地鼠出现的最大次数。
接下来k⾏,每⾏表示⼀组数据,包含n个整数,代表a[1]到a[n]。
【输出文件】
输出文件为dishu.out。
对于每组数据输出小A最多能打到的地鼠个数。
【输入样例】
3 3 5 2
3 2 1
1 2 3
2 3 1
【输出样例】
2
3
3
【数据规模和约定】
对于30%的数据,n*t≤1,000。
对于60%的数据,n*t≤100,000。
对于80%的数据,n*max≤100,000。
对于100%的数据,1≤k≤10,1≤n,max≤10^5,1≤t≤10^9,n*max≤20,000,000。

Solution
先澄清一下题意:即使下一轮地鼠们又一次走过。也必须打比上轮打过的最肥的老鼠还要肥的才行 。简单的来说,每一个数据中,maxn 是不会因为打第k次而变成0的。
只能打T次。
相当于地鼠们排好队从你面前走过了T次
那么相当于,原本长度为N的队列现在循环成了长度与T*N的队列。
必须要打的最多。
思路很清晰。
最长上升序列。

问:怎么在下一次队列循环中处理前面已经打过的老鼠。
答:不用管!
原因:在LIS 队列中 ,只又F【i】>F【i-1】时才会对答案有贡献,
所以
譬如
1 3 2 4 5, 1 3 2 4 5, 1 3 2 4 5 的序列中 F[i] 为
我们发现 ,,在后面出现的重复的元素,是不会对LIS的
d【i】数组 (即最长上升长度为i,且结尾最小的元素) 做出任何贡献的。
换一种方式说。
最长上升序列中不会出现重复的元素。
所以其实不处理重复的元素。

贴一下代码
(我的LIS他们都说好奇怪,我也这么觉得)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstdlib>
#define M (1000005)
#define LL long long
using namespace std;
int n,s[M],d[M],cnt,f[M],k,maxn,t,vis[M],Maxn,return_flag;
void test(int t)
{
    for (int i=1;i<=n*t;i++)
        cout<<s[(i-1)%n+1]<<' ';
    cout<<endl;
}
int LIS(int t)
{
    maxn=0;cnt=0;
    memset(d,0,sizeof(d));memset(f,0,sizeof(f));
    for (int i=1;i<=n*t;i++){
        int ni=(i-1)%n+1;
        if(s[ni]>d[cnt]){
            d[++cnt]=s[ni];f[ni]=cnt;
            maxn=max(maxn,f[ni]);
            if(maxn==return_flag) return maxn;
        }
        else{   
            int k=lower_bound(d+1,d+cnt+1,s[ni])-d;
            f[ni]=k;
            d[k]=s[ni];
            maxn=max(maxn,f[ni]);
            if(maxn==return_flag) return maxn;
        }         
    }
    return maxn;
}
int main()
{
    freopen("dishu.in","r",stdin);
        freopen("dishu.out","w",stdout);
    cin>>k>>n>>Maxn>>t;
    return_flag=min(Maxn,n);
    while(k--){
        int ans=0;
        for (int i=1;i<=n;i++)
            scanf("%d",&s[i]);
        ans=LIS(t);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值