Codeforces 573B Bear and Blocks

http://codeforces.com/problemset/problem/573/B

 题目大意:

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

思路:考虑第一次取得时候

h[i]=min(h[i-1],h[i]-1,h[i+1])

那么取k次的时候:

h[i]=max(0,min(h[i-j]-(k-j),h[i+j]-(k-j)))

h[i]=max(0,min(h[i-j]+j-k,h[i+j]+j-k))

k为常数,可以先暂时忽略,那就是要求h[i-j]+j和h[i+j]+j的最小值。

然后两遍左右for一下,同时给区间加一

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<iostream>
 6 struct segtree{
 7     int l,r,mn,tag;
 8 }t[5000005];
 9 int h[200005],n,l[200005],r[200005];
10 int read(){
11     int t=0,f=1;char ch=getchar();
12     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
13     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
14     return t*f;
15 }
16 void pushdown(int k,int l,int r){
17     if (l==r||t[k].tag==0){
18         return;
19     }
20     t[k*2].tag+=t[k].tag;
21     t[k*2].mn+=t[k].tag;
22     t[k*2+1].tag+=t[k].tag;
23     t[k*2+1].mn+=t[k].tag;
24     t[k].tag=0;
25 }
26 void updata(int k,int l,int r){
27     if (l==r) return;
28     t[k].mn=std::min(t[k*2].mn,t[k*2+1].mn);
29 }
30 void build(int k,int l,int r){
31     t[k].mn=0;
32     t[k].tag=0;
33     if (l==r){
34         t[k].mn=h[l];
35         return;
36     }
37     int mid=(l+r)>>1;
38     build(k*2,l,mid);
39     build(k*2+1,mid+1,r);
40     updata(k,l,r);
41 }
42 void add(int k,int l,int r,int x,int y){
43     pushdown(k,l,r);
44     if (l==x&&r==y){
45         t[k].mn++;
46         t[k].tag++;
47         pushdown(k,l,r);
48         return;
49     }
50     int mid=(l+r)>>1;
51     if (y<=mid) add(k*2,l,mid,x,y);
52     else
53     if (x>mid) add(k*2+1,mid+1,r,x,y);
54     else add(k*2,l,mid,x,mid),add(k*2+1,mid+1,r,mid+1,y);
55     updata(k,l,r);
56 }
57 int query(int k,int l,int r,int x,int y){
58     pushdown(k,l,r);
59     if (l==x&&r==y) return t[k].mn;
60     int mid=(l+r)>>1;
61     if (y<=mid) return query(k*2,l,mid,x,y);
62     else
63     if (x>mid) return query(k*2+1,mid+1,r,x,y);
64     else return std::min(query(k*2,l,mid,x,mid),query(k*2+1,mid+1,r,mid+1,y));
65 }
66 int main(){
67     n=read();
68     for (int i=1;i<=n;i++) h[i]=read();
69     h[0]=h[n+1]=0;
70     build(1,0,n+1);
71     for (int i=1;i<=n;i++){
72         add(1,0,n+1,0,i-1);
73         l[i]=query(1,0,n+1,0,i);
74     }
75     build(1,0,n+1);
76     for (int i=n;i>=1;i--){
77         add(1,0,n+1,i+1,n+1);
78         r[i]=query(1,0,n+1,i,n+1);
79     }
80     int ans=0;
81     for (int i=1;i<=n;i++)
82      ans=std::max(ans,std::min(l[i],r[i]));
83     printf("%d\n",ans);
84     return 0;
85 }

换种思路:我们的每一个竖列,要嘛在旁边两列消掉以后,一次性消掉,或者是一个一个地消

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<iostream>
 6 int n,vis[200005];
 7 int read(){
 8     int t=0,f=1;char ch=getchar();
 9     while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();}
10     while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
11     return t*f;
12 }
13 int main(){
14     n=read();
15     for (int i=1;i<=n;i++) vis[i]=read();
16     vis[1]=1;
17     for (int i=2;i<=n;i++) vis[i]=std::min(vis[i],vis[i-1]+1);
18     vis[n]=1;
19     for (int i=n-1;i>=1;i--) vis[i]=std::min(vis[i],vis[i+1]+1);
20     int ans=0;
21     for (int i=1;i<=n;i++) ans=std::max(ans,vis[i]);
22     printf("%d\n",ans);
23     return 0;
24 }
时间: 2024-12-29 01:54:06

Codeforces 573B Bear and Blocks的相关文章

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

题目链接: 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

Codeforces 385B Bear and Strings

题目链接:Codeforces 385B Bear and Strings 记录下每一个bear的起始位置和终止位置,然后扫一遍记录下来的结构体数组,过程中用一个变量记录上一个扫过的位置,用来去重. #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX_N = 5000 + 100; char str[MAX_N]; struct Node

Codeforces 385C Bear and Prime Numbers(素数预处理)

Codeforces 385C Bear and Prime Numbers 其实不是多值得记录的一道题,通过快速打素数表,再做前缀和的预处理,使查询的复杂度变为O(1). 但是,我在统计数组中元素出现个数时使用了map,以至于后面做前缀和的累加时,每次都要对map进行查询,以至于TLE.而自己一直没有发现,以为是欧拉筛对于这道题还不够优,于是上网搜题解,发现别人的做法几乎一样,但是却能跑过,挣扎了许久才想起是map的原因.map的内部实现是一颗红黑树,每次查询的复杂度为O(logN),在本来时

Codeforces Round #318-(D. Bear and Blocks)

这道题我上来就是想到的是暴力,每次都把表面的那一层减掉,直到所有的高度为0为止.但是T了. 题意: 现在有n个方格,然后每个方格都有一个高度,然后每次都可以把那些非完整块(就是它的四个方向没有被完全包围)给连在一起消去.问你最后把所有的方块消去需要几次. 思路: 我们只需要从左边,右边分别进行一次消去,然后最后进行一次判断就好了.最多的次数不可能超过最大的那个的高度. 首先初始化为h1[0]=0,h2[n+1]=0, 我们设两个数组h1代表的是从左边开始消去每次的最大高度,h2则是右边的. h1

Codeforces Round #318 (Div. 2) D Bear and Blocks

不难发现在一次操作以后,hi=min(hi-1,hi-1,hi+1),迭代这个式子得到k次操作以后hi=min(hi-j-(k-j),hi-k,hi+j-(k-j)),j = 1,2,3... 当k == min(hi-j+j,hi+j+j)时hi会变成0,因为min具有传递性,那么可以左右分开来考虑,hi-j+j化一下就是hi-j-(i-j)+i,其中后面i和j无关,所以只要找出前面最小的hi-i 对于右边的类似处理,最后再扫一遍,得出最大的一个k就是答案. #include<bits/std

codeforces 657C - Bear and Contribution [想法题]

题目链接: http://codeforces.com/problemset/problem/657/C -------------------------------------------------------------------------------------------------------- 题目的特别之处在于只有 $+1$ $+5$ 这两种操作 我们要考虑如何利用这个条件 多想一下后可以发现 如果最优解的目标值为$x($将至少$k$个人的值增加到$x)$ 那么一定存在一个

CodeForces 573A Bear and Poker

题目链接:http://codeforces.com/problemset/problem/573/A 题目大意:此题要求一组数中的元素乘以2或者乘以3后得到的数都一样,其实就是判断这些数除去2和3这些因子后剩下的因子都是一样的即可. AC代码: #include <cstdio> #include <cmath> #include <cstring> #include <iostream> using namespace std; #define M 10

Codeforces A - Bear and Prime 100(交互题)

A - Bear and Prime 100 思路:任何一个合数都可以写成2个以上质数的乘积.在2-100中,除了4,9,25,49外都可以写成两个以上不同质数的乘积. 所以打一个质数加这四个数的表:{2,3,4,5,7,9,11,13,17,19,23,25,29,31,37,41,43,47,49},询问19次,如果能被整出两次以上,说明是合数,否则是质数. #include<bits/stdc++.h> using namespace std; #define ll long long

Codeforces 679B - Bear and Tower of Cubes

679B - Bear and Tower of Cubes 题目大意:一个数x定义一种拆分方式,每次拆分取最大的a 且 a^3<=x,x减去a^3,之后重复同样的操作,直到 x变为0.给你一个数m( m<=1e15 ),让你取一个数q<=m,q能执行的操作数在小于等于m的数里面最大,且在操作数 最大的里面,值是最大的. 感觉这种思维题就是特别难.... 思路:设a为当前小于等于m的最大立方数.则对于当前的 m 我们有两种情况要考虑,第一种是res1=m-a^3 第二种是不想减去a^3,