Educational Codeforces Round 55 (Rated for Div. 2) E Increasing Frequency(dp)

题目链接:http://codeforces.com/contest/1082/problem/E

E. Increasing Frequency

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given array aa of length nn. You can choose one segment [l,r][l,r] (1≤l≤r≤n1≤l≤r≤n) and integer value kk (positive, negative or even zero) and change al,al+1,…,aral,al+1,…,ar by kk each (i.e. ai:=ai+kai:=ai+k for each l≤i≤rl≤i≤r).

What is the maximum possible number of elements with value cc that can be obtained after one such operation?

Input

The first line contains two integers nn and cc (1≤n≤5⋅1051≤n≤5⋅105, 1≤c≤5⋅1051≤c≤5⋅105) — the length of array and the value cc to obtain.

The second line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤5⋅1051≤ai≤5⋅105) — array aa.

Output

Print one integer — the maximum possible number of elements with value cc which can be obtained after performing operation described above.

Examples

input

Copy

6 9
9 9 9 9 9 9

output

Copy

6

input

Copy

3 2
6 2 6

output

Copy

2

Note

In the first example we can choose any segment and k=0k=0. The array will stay same.

In the second example we can choose segment [1,3][1,3] and k=−4k=−4. The array will become [2,−2,2][2,−2,2].

 

题意:给你n(n<=1e5)个数和一个数c,你只能把一段连续区间里的数都加上k(k由你自己定),使得整个序列含c尽可能的多。

思路:刚开始想线段树、RMQ那边去了,因为显然是从某处开始,前面的c的数量和后面的c的都已经确定,把中间这段数中出现次数最多的数都变成c。但是你要枚举前面用了多少c,后面用了多少c已经是O(n*n),而且中间出现次数最多的数不好计算。于是我就自闭了。

看了别人的代码瞬间醒悟。。。只需要dp一下就行了。

dp[i]表示从前面某个位置pos开始,到现在的位置i,把pos~i之间的(出现次数最多的)数变成c,前pos-1个不变的最大的含c的数量。

pre[x]=j表示对于某个数a[i]==x,它上一次出现的位置是j。即a[j]=a[i]=x。

qian[i]表示从第一个位置到当前位置i时c出现的次数。

hou[i]表示从最后一个位置到当前位置i时c出现的次数。

那么状态转移方程就出来了:

dp[i]=max(qian[i-1]+1,dp[pre[a[i]]]+1);

pre[i]=i;

ans=max(ans,dp[i]+hou[i+1]);

这样就可以保证某个位置pos开始,dp[pos+1]~dp[i]这一段出现次数最多的数都变成了c的最大的c的数量。

以上思路值得好好思考。

代码:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
using namespace std;
const int maxn=500000+10;
int n,k,m;
int cnt,tmp,flag,ans;
int dp[maxn];
int a[maxn],c[maxn],pre[maxn],qian[maxn],hou[maxn];
int main()
{

    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        qian[i]=qian[i-1]+(a[i]==k);
    }
    for(int i=n;i>=1;i--)
    {
        hou[i]=hou[i+1]+(a[i]==k);
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=max(qian[i-1]+1,dp[pre[a[i]]]+1);
        pre[a[i]]=i;
        ans=max(ans,dp[i]+hou[i+1]);
    }
    printf("%d\n",ans);
    return 0;
}

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值