首页 > 其他分享 >codeforces 573B B. Bear and Blocks(线段树+dp)

codeforces 573B B. Bear and Blocks(线段树+dp)

时间:2023-04-23 21:32:41浏览次数:43  
标签:Blocks 573B int MAX min codeforces ret hi include


题目链接:

codeforces 573B


题目大意:

给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块。


题目分析:

  • 首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式: hi=min(hi−1,hi−1,hi+1)
  • 每次操作都满足如下的递推式,我们递推一下得到第k次操作第i的塔的高度: hi=max(0,minj=0i{min(hi−j−(k−j),hi+j−(k−j)}⇒hi=max(0,minj=0i{min(hi−j+j−k,hi+j+j−k}
    因为k是常数,所以对于,每一项我们找到的就是最小的hi−j+j和hi+j+j,这可用线段树进行维护。
  • 而且要设定两个虚拟的高度为0的塔,分别放在这一堆塔的两头,这样能够维护两侧的在每次操作拿光的情况。
  • 至于线段树维护的部分,就是遍历i两次,分别从小到大和从大到小,每次修改之前遍历过的位置为所要的状态,也就是之前遍历过的位置区间内全部加1,然后统计[0,i]的最小值,右侧的同理。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#define MAX 100007

using namespace std;

int n;
int l[MAX],r[MAX],h[MAX];

struct Tree
{
    int l,r,minn,lazy;
}tree[MAX<<2];

void push_up ( int u )
{
    tree[u].minn = min ( tree[u<<1].minn , tree[u<<1|1].minn );
}

void build ( int u , int l , int r )
{
    tree[u].l = l;
    tree[u].r = r;
    tree[u].lazy = 0;
    int mid = l+r>>1;
    if ( l == r ) 
    {
        tree[u].minn = h[l];
        return;
    }
    build ( u<<1 , l , mid );
    build ( u<<1|1 , mid+1 , r );
    push_up ( u );
}

void push_down ( int u )
{
    int ll = tree[u].lazy;
    tree[u].lazy = 0;
    if ( ll )
    {
        tree[u<<1].lazy += ll;
        tree[u<<1|1].lazy += ll;
        tree[u<<1].minn += ll;
        tree[u<<1|1].minn += ll;
    }
}

void update ( int u , int left , int right )
{
    int l = tree[u].l;
    int r = tree[u].r;
    int mid = l+r>>1;
    if ( left <= l && r <= right )
    {
        tree[u].minn += 1;
        tree[u].lazy += 1;
        return;
    }
    push_down ( u );
    if ( left <= mid && right >= l ) 
        update ( u<<1 , left , right );
    if ( left <= r && right > mid )
        update ( u<<1|1 , left , right );
    push_up ( u );
}

int query ( int u , int left , int right )
{
    int l = tree[u].l;
    int r = tree[u].r;
    int mid = l+r>>1;
    if ( left <= l && r <= right )
        return tree[u].minn;
    push_down ( u );
    int ret = 1<<29;
    if ( left <= mid && right >= l ) 
        ret = min ( ret , query ( u<<1 , left , right ) );
    if ( left <= r && right > mid )
        ret = min ( ret , query ( u<<1|1 , left , right ) );
    return ret;
}

int main ( )
{
    while ( ~scanf ( "%d" , &n ) )
    {
        h[0] = h[n+1] = 0;
        for ( int i = 1; i <= n ; i++ )
            scanf ( "%d" , &h[i] );
        build ( 1 , 0 , n+1 );
        for ( int i = 1 ; i <= n ; i++ )
        {
            update ( 1 , 0 , i-1 );
            l[i] = query ( 1 , 0 , i );
        }
        build ( 1 , 0 , n+1 );
        for ( int i = n ; i > 0 ; i-- )
        {
            update ( 1 , i+1 , n+1 );
            r[i] = query ( 1 , i , n+1 );
        }
        int ans = 0;
        for ( int i = 1 ; i <= n ; i++ )
        {
            //cout << "YES : " << l[i] << " " << r[i] << endl;
            ans = max ( ans , min ( l[i] , r[i] ));
        }
        printf ( "%d\n" , ans );
    }
}


标签:Blocks,573B,int,MAX,min,codeforces,ret,hi,include
From: https://blog.51cto.com/u_7936627/6218757

相关文章

  • codeforces 267A A. Subtractions(辗转相除)
    题目链接:codeforces267A题目大意:给出一个数对,(a,b)每次用较大的减较小的,直到出现0为止,问要进行多少次操作。题目分析:大的减小的操作,可以利用取模优化过程,也就是辗转相除,商是操作次数,余数是下一段与之前较小的数继续进行操作的数,水题不做赘述。AC代码:#include<iostream>#include......
  • codeforces 225B B. Well-known Numbers(数论+二分+贪心+构造)
    题目链接:codeforces225B题目大意:定义f(k,n)为类似菲波那契数推导,只不过变为前k项的和,然后给出一个数s,利用k-菲波那契数构造出一个不重复的集合的元素和为s,集合的规模大于1题目分析:首先因为菲波那契数的增长速度快的吓人,所以给的数据范围109很快就能达到,我们得到O(n)的构造出所有的......
  • Quasi Binary---codeforces
    #QuasiBinary##题面翻译**题目描述**给出一个数n,你需要将n写成若干个数的和,其中每个数的十进制表示中仅包含0和1。问最少需要多少个数**输入输出格式**输入格式:一行一个数n(1≤n≤10^6)输出格式:最少的数的个数,并给出一种方案。##题目描述Anumberiscalledquasib......
  • Codeforces Round 866 (Div. 2)(A~C)
    目录A.Yura'sNewName题意思路代码B.JoJo'sIncredibleAdventures题意思路代码C.ConstructiveProblem题意思路代码A.Yura'sNewName题意在字符串\(s\)中添加"_"或者"^",使得\(s\)中的任意字符都必须为"_"或者"^^"的一部分,求最少要添加的字符数量思路当字符串......
  • Codeforces Round 689 (Div. 2, based on Zed Code Competition)D.Divide and Summari
    题意:我们给定包含n个正整数的数组,我们可以对这个数组执行一些操作之后,可以让数组内元素的和成为我们想要的数。我们对数组的执行操作一共分为三个步骤,第一个步骤是我们首先计算出数组的中间值mid。这里mid的定义不是中位数也不是均值,而是最大值和最小值的均值。也就是mid=(min......
  • codeforces #864 div2 B
    GCDPartition这道题首先要解决一个问题,要把区间分成几块,可以证明分成两块是更优首先我们假设把区间分成了m(>=2)块b1,b2,b3,...,bm,则答案是gcd(b1,b2,b3,...,bm),则b1,b2是gcd(b1,b2,b3,...,bm)的倍数,那么b1+b2也是gcd(b1,b2,b3,...,bm)的倍数,所以gcd(b1,b2,......
  • Educational Codeforces Round 147 (Rated for Div. 2)
    EducationalCodeforcesRound147(RatedforDiv.2)链接EducationalCodeforcesRound147(RatedforDiv.2)A题如果第一位数是0,直接打印0如果第一位数是'?',有9个数可以选择,如果其他位数是'?',有10中情况选择,相乘就可以了#include<iostream>#include<algo......
  • CodeForces 34B Sale
    B- SaleTimeLimit:2000MS     MemoryLimit:262144KB     64bitIOFormat:%I64d&%I64uSubmit Status Practice CodeForces34BDescriptionOnceBobgottoasaleofoldTVsets.Therewere n TVsetsatthatsale.TVsetwithi......
  • C. Table Decorations(Codeforces)(规律)
    C.TableDecorationstimelimitpertestmemorylimitpertestinputoutputr red, g greenand b blueballoons.Todecorateasingletableforthebanquetyo......
  • CodeForces 34A Reconnaissance 2
     Reconnaissance2TimeLimit:2000MS     MemoryLimit:262144KB     64bitIOFormat:%I64d&%I64uSubmit Status Practice CodeForces34ADescriptionn soldiersstandinacircle.Foreachsoldierhisheight ai isknown.Areco......