100036. 【NOIP2017提高A组模拟7.10】随机

题目大意

给定一个长度为m的序列S,定义其特征值为
m a x { m i n { | S i S j | ( 1 <= i < j <= m ) , m }}
选定的子序列长度必须至少为2,即j - i > 0.

数据范围

30%: n <= 1000
60%: n <= 10 5
100%: 2 <= n <= 10 6 , 1 <= a i <= 10 9

Solution

100%:
注意到随着区间长度的增长,m会变大, m i n { | S i S j | }会变小.
设当前区间为[l..r],比较m和 m i n { | S i S j | },若m较小则把r + 1,否则l + 1.
使用multiset做到O( n l o g n )

Code

#include <cstdio>
#include <cmath>
#include <set>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 2e6 + 5;
const long long INF = 10000000000;

long long n,l = 1,r = 2,ans = 0x3f3f3f3f;
long long a[N];
multiset <long long>::iterator faq;
multiset <long long> val,dif;

long long Check()
{
    return *(dif.begin());
}

void Add(long long x)
{
    faq = val.insert(x);
    long long t = *(++faq);faq--;long long t1 = *(--faq);faq++;
    dif.erase(dif.find(abs(t - t1)));
    dif.insert(abs(x - t));
    dif.insert(abs(x - t1));
}

void Remove(long long x)
{
    faq = val.find(x);
    long long t = *(++faq);faq--;long long t1 = *(--faq);faq++;
    dif.insert(abs(t - t1));
    dif.erase(dif.find(abs(x - t)));
    dif.erase(dif.find(abs(x - t1)));
    val.erase(faq);
}

int main()
{
    freopen("random.in","r",stdin);
    freopen("random.out","w",stdout);
    scanf("%lld",&n);
    for (int i = 1 ; i <= n ; i++) scanf("%lld",&a[i]);
    val.insert(-INF),val.insert(INF);
    dif.insert(INF + INF);
    Add(a[1]),Add(a[2]);
    while (r <= n)
    {
        ans = min(ans,max(r - l + 1,Check()));
        if (r - l + 1 < Check()) 
        {
            r++;
            Add(a[r]);
        }
        else 
        {
            Remove(a[l]);
            l++;
        }
    }
    printf("%lld\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/P_hillipe/article/details/81607733
今日推荐