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 ",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 ",ans); 23 return 0; 24 }