我是靠谱客的博主 欢呼睫毛膏,最近开发中收集的这篇文章主要介绍Codeforce 487B Strip 动归+二分+线段树,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

写完之后的第一感觉就是我又写麻烦了。。。写了两棵线段树维护信息。。。

dp[i] 表示[1,i]这段前缀的最优解,若dp[i] = INF,表示无解。

特殊的,dp[0] = 0。

那么,有一个思路就是我们有一些长度为设dp[i]已知且dp[i] != INF,那么设我们知道一个位置R,满足[i+1,R]这一段区间可以划分到一段,i+1 <= R <= n,且R-i >= l。

那么我们将dp[i+1],dp[i+2]...dp[R]分别更新为min(dp[i+1],dp[i]+1),min(dp[i+2],dp[i]+1)....min(dp[R],dp[i]+1)。

如果dp[n] 为INF,那么说明误解,否则dp[n]表示最优解。

寻找位置R需要二分套线段树,更新dp[]需要线段树。时间复杂度为o(n*log(n)*log(n))。

#include <iostream>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
#define INF 0x3f3f3f3f

using namespace std;

int num[100010];

struct N
{
    int Min,Max;
}st[4*100010];

void Init(int site,int L,int R)
{
    if(L == R)
    {
        st[site].Min = num[L];
        st[site].Max = num[L];
        return ;
    }

    int mid = (L+R)>>1;

    Init(site<<1,L,mid);
    Init(site<<1|1,mid+1,R);

    st[site].Max = max(st[site<<1].Max,st[site<<1|1].Max);
    st[site].Min = min(st[site<<1].Min,st[site<<1|1].Min);
}

void Query(int site,int L,int R,int l,int r,int &Max,int &Min)
{
    if(L == l && R == r)
    {
        Max = max(Max,st[site].Max);
        Min = min(Min,st[site].Min);
        return ;
    }

    int mid = (L+R)>>1;

    if(r <= mid)
        Query(site<<1,L,mid,l,r,Max,Min);
    else if(mid < l)
        Query(site<<1|1,mid+1,R,l,r,Max,Min);
    else
    {
        Query(site<<1,L,mid,l,mid,Max,Min);
        Query(site<<1|1,mid+1,R,mid+1,r,Max,Min);
    }
}

int dp[100100];

int lazy[400100];

void Update(int site,int L,int R,int l,int r,int info)
{
    if(lazy[site] <= info)
    {

        return ;
    }
    if(L == l && R == r)
    {
        lazy[site] = info;
        return ;
    }

    int mid = (L+R)>>1;

    Update(site<<1,L,mid,L,mid,lazy[site]);
    Update(site<<1|1,mid+1,R,mid+1,R,lazy[site]);

    if(r <= mid)
        Update(site<<1,L,mid,l,r,info);
    else if(mid < l)
        Update(site<<1|1,mid+1,R,l,r,info);
    else
    {
        Update(site<<1,L,mid,l,mid,info);
        Update(site<<1|1,mid+1,R,mid+1,r,info);
    }
}

int Query(int site,int L,int R,int goal)
{
    if(L == R)
    {
        return dp[goal] = min(dp[goal],lazy[site]);
    }
    int mid = (L+R)>>1;

    Update(site<<1,L,mid,L,mid,lazy[site]);
    Update(site<<1|1,mid+1,R,mid+1,R,lazy[site]);

    if(goal <= mid)
        return Query(site<<1,L,mid,goal);
    return Query(site<<1|1,mid+1,R,goal);
}

int main()
{
    int n,l,s;

    scanf("%d %d %d",&n,&s,&l);

    int i;

    for(i = 1;i <= n; ++i)
        scanf("%d",&num[i]);

    if(l > n)
        return puts("-1"),0;
    Init(1,1,n);
    int Max,Min;

    memset(dp,INF,sizeof(dp));
    dp[0] = 0;
    memset(lazy,INF,sizeof(lazy));
    for(i = 0;i <= n; ++i)
    {
        if(i + l > n)
            break;
        int tmp = (i == 0 ? 0 : Query(1,1,n,i));

        if(tmp == INF)
            continue;
        int L = i+l,R = n;
        int mid,anw = -1;
        while(L <= R)
        {
            mid = (L+R)>>1;
            Max = -INF,Min = INF;
            Query(1,1,n,i+1,mid,Max,Min);

            if(Max-Min > s)
                R = mid-1;
            else
                L = mid+1,anw = mid;
        }
        if(anw == -1)
            continue;

        Update(1,1,n,i+l,anw,dp[i]+1);
    }



    if(Query(1,1,n,n) == INF)
        puts("-1");
    else
        printf("%dn",Query(1,1,n,n));

    return 0;
}
























最后

以上就是欢呼睫毛膏为你收集整理的Codeforce 487B Strip 动归+二分+线段树的全部内容,希望文章能够帮你解决Codeforce 487B Strip 动归+二分+线段树所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部