与众不一样

问题 E: 与众不一样
时间限制: 1 Sec 内存限制: 128 MB

题目描述
给你一个长度为N的序列,定义“完美序列”是一段区间满足区间内使用的数互不相同 询问M次,问区间[L,R]之间最长完美序列的长度
输入
9 2
2 5 4 1 2 3 6 2 4
0 8
2 6
输出
6
5
提示
N,M<=200000,序列中数的大小绝对值不超过 10 6
题解:
这题还是有很多坑的吧,大家要小心,仔细看样例。
这是一道较复杂的 R M Q
我们令 l a s t [ v a l u e ] 表示盈利值 v a l u e 最近出现的位置,一开始全部是 0
我们先令 s t [ i ] 表示以第 i 个数为结尾的最长完美序列
s t [ i ] = m a x ( s t [ i 1 ] , l a s t [ a [ i ] ] + 1 )
f [ i ] 表示第 i 个数为结尾最长完美序列的长度
很显然 f [ i ] = i s t [ i ] + 1
s t [ i ] f [ i ] 都是在 O ( N ) 能解决的
s t 的递推式可知, s t 的值是一个非递增的序列,那么对于一个询问区间 [ l , r ] ,该区间的 s t 值可能会出现:左边一部分的 s t 值不在区间内,即小于 l ,而右边一部分的 s t 值大于等于 l ,由于 s t 值有单调性,所以这个分界点我们可以用二分得到
令这个分界点为 m i d
那么整个区间最长完美长度,可以分两部分来解决。其中左边部分的最大值很显然为 m i d l ,而右边部分由于 s t 值大于等于 l ,所以就是求 [ m i d , r ] 之间 f 数组的最大值
我们再令 m x [ i ] [ j ] 表示以 i 开始之后 2 j 个中 f 数组的最大值
这个我们便可以用 R M Q
C o d e

#include<bits/stdc++.h>
#define N 200005
using namespace std;
int last[N*10],b[N*10],a[N*10],st[N*10],f[N*10],maxn[N][30];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        st[i]=max(st[i-1],last[a[i]+1000000]+1);
        f[i]=i-st[i]+1;
        maxn[i][0]=f[i];
        last[a[i]+1000000]=i;
    }
    for(int j=1;j<20;j++)
        for(int i=1;i<=n+1-(1<<j);i++)
            maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        x++,y++;
        int l=x,r=y;
        while(x<y)
        {
            int mid=(x+y)>>1;
            if(st[mid]<l)x=mid+1;else y=mid;
        }
        if(st[x]<l)x=x+1;
        int nmax=0;
        if(x<=r)
        {
            int k=log2(double(r-x+1));
            nmax=max(maxn[x][k],maxn[r-(1<<k)+1][k]);
        }
        printf("%d\n",max(nmax,x-l));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/80955416