ZOJ 3790 Consecutive Blocks

Time Limit: 2 Seconds       Memory Limit: 65536 KB

There are N (1 ≤ N ≤ 105) colored blocks (numbered 1 to N from left to right) which are lined up in a row. And the i-th block's color is Ci (1 ≤ Ci ≤ 109). Now you can remove at most K(0 ≤ K ≤ N) blocks, then rearrange the blocks by their index from left to right. Please figure out the length of the largest consecutive blocks with the same color in the new blocks created by doing this.

For example, one sequence is {1 1 1 2 2 3 2 2} and K=1. We can remove the 6-th block, then we will get sequence {1 1 1 2 2 2 2}. The length of the largest consecutive blocks with the same color is 4.

Input

Input will consist of multiple test cases and each case will consist of two lines. For each test case the program has to read the integers N and K, separated by a blank, from the first line. The color of the blocks will be given in the second line of the test case, separated by a blank. The i-th integer means Ci.

Output

Please output the corresponding length of the largest consecutive blocks, one line for one case.

Sample Input
8 1
1 1 1 2 2 3 2 2
Sample Output
4


题意:给你n个数字组成的有序数列,你可以选择性地最多删除k个数,问删完之后的数列最多有多少个相同的数连在一起。


最开始想着用表存,后来发现其实不需要,直接用一个结构体记录val(值)和num(在原数组中的位置),然后根据val sort一下,从第一个开始判一遍就好了。


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <algorithm>
#include <vector>
#include <map>
#define PI acos(-1.0)
#define M 1000005  //10^6
#define eps 1e-8
#define LL long long
#define moo 1000000007
#define INF -999999999
#define LL long long
using namespace std;
struct ttt
{
    int num;
    int val;
}tt[M];
bool cmp(ttt a,ttt b)
{
    if(a.val!=b.val)
        return a.val>b.val;
    if(a.val==b.val)
        return a.num<b.num;
}
int main()
{
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int num=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&tt[i].val);
            tt[i].num=i;
        }
        sort(tt+1,tt+m+1,cmp);

        int ans=1;
        int now=n;   //记录剩余可删的数
        int pick;    //记录当前判断的val值
        int puck=1;  //记录当前连续数值
        pick=tt[1].val;
        int head=1;  //记录当前连续段是从哪个开始的(其实这个可以去掉,用i-pick代替,这里加上是为了方便)
        for(int i=2;i<=m;i++)
        {
            if(tt[i].val==pick)   //当新入队的数跟前面的一样,就判断以它为结尾最多能连多少个
            {
                if(tt[i].num-tt[i-1].num-1<=now)
                {
                    puck++;
                    ans=max(ans,puck);
                    now=now-(tt[i].num-tt[i-1].num-1);
                }
                else
                {
                    int flag=0;
                    for(head;head<=i-1;head++)
                    {
                        puck--;
                        now=now+(tt[head+1].num-tt[head].num-1);
                        if(now>=tt[i].num-tt[i-1].num-1)
                        {
                            flag=1;
                            break;
                        }
                    }
                    if(flag==0)
                    {
                        now=n;
                        puck=1;
                        head=i;
                    }
                    else
                    {
                        puck++;
                        now=now-(tt[i].num-tt[i-1].num-1);
                        head++;
                    }
                    ans=max(ans,puck);
                }
            }
            else    //新入队的数跟前面的不一样,说明前面一个数已经判完了,于是所有参数初始化
            {
                now=n;
                pick=tt[i].val;
                head=i;
                puck=1;
            }
        }
        cout<<ans<<endl;
    }
}
/*
10 3
1 2 3 4 1 6 7 1 9 1
10 3
2 1 3 1 4 5 6 9 1 1

ans
3
2
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值