51Nod 1555 布丁怪
来源:互联网 发布:hadoop 端口 编辑:程序博客网 时间:2024/04/28 02:21
分治
分治的方法很巧妙,就是写起来有一点小恶心
先放CF题解:http://codeforces.com/blog/entry/17281
题意就是问有多少连续区间满足区间内数字连续,这类序列计数一般考虑分治。
一个分治区间[l,r],考虑怎么统计过mid的答案。
暴力枚举左端点,然而右端点并不单调,不太好维护,考虑其他方法。
出现上述情况,当且仅当已经有合法的跨mid的区间[a,b],然后b右边下一个元素可以补充在连续区间的左右两侧,也就是区间可以扩张。主要原因是最大最小值会变化。
那就大力分类讨论最大最小值。最大最小值同侧的,单调枚举即可。对于异侧的,除了考虑到b-a=mx[b]-mi[a]或b-a=mx[a]-mi[b]之外,还有的限制是区间内不能有超过极值的值,这个限制导致随着左端点左移,右边的贡献区间的两个端点都是单调右移的,维护一下即可。
#include<cstdio>#include<algorithm>#define N 300005using namespace std;namespace runzhe2000{ typedef long long ll; const int INF = 1<<29; int read() { int r = 0; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()); for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar()); return r; } void mswap(int &a, int &b){int t = a; a = b; b = t;} int n, a[N], mi[N], mx[N], sum[N<<1], sumR[N<<1], sumL[N<<1]; ll ans; void dc(int l, int r) { if(l == r) {ans++; return;} int mid = (l+r)>>1; mi[mid] = mx[mid] = a[mid]; for(int i = mid-1; i >= l; i--) mi[i] = min(a[i], mi[i+1]), mx[i] = max(a[i], mx[i+1]); mi[mid+1] = mx[mid+1] = a[mid+1]; for(int i = mid+2; i <= r; i++) mi[i] = min(a[i], mi[i-1]), mx[i] = max(a[i], mx[i-1]); // min & max in L int curl = mid, curr = mid; for(; curl >= l; curl--) { for(; curr < r && mi[curl] < a[curr+1] && a[curr+1] < mx[curl]; curr++); if(curl < mid && curr > mid && curr - curl == mx[curl] - mi[curl]) ans++; } // min & max in R curl = mid+1, curr = mid+1; for(; curr <= r; curr++) { for(; curl > l && mi[curr] < a[curl-1] && a[curl-1] < mx[curr]; curl--); if(curl < mid+1 && curr > mid+1 && curr - curl == mx[curr] - mi[curr]) ans++; } // min in L, max in R { for(int i = mid+1; i <= r; i++) sum[mx[i]-i+n]++; int L = mid+1, R = mid; for(int i = mid+1; i <= r; i++) sumL[mx[i]-i+n]++; for(int i = mid; i >= l; i--) { for(; R < r && mi[i] < mi[R+1]; R++) sumR[mx[R+1]-(R+1)+n]++; for(; L <= r && mx[i] > mx[L] ; L++) sumL[mx[L]-L+n]--; if(L <= R) ans += sumL[mi[i]-i+n] + sumR[mi[i]-i+n] - sum[mi[i]-i+n]; } for(int i = mid+1; i <= R; i++) sumR[mx[i]-i+n]--; for(int i = L; i <= r; i++) sumL[mx[i]-i+n]--; for(int i = mid+1; i <= r; i++) sum[mx[i]-i+n]--; } // max in L, min in R { for(int i = mid+1; i <= r; i++) sum[mi[i]+i]++; int L = mid, R = mid+1; for(int i = mid+1; i <= r; i++) sumR[mi[i]+i]++; for(int i = mid; i >= l; i--) { for(; R <= r && mi[i] < mi[R]; R++) sumR[mi[R]+R]--; for(; L < r && mx[i] > mx[L+1] ; L++) sumL[mi[L+1]+(L+1)]++; if(R <= L) ans += sumL[mx[i]+i] + sumR[mx[i]+i] - sum[mx[i]+i]; } for(int i = mid+1; i <= L; i++) sumL[mi[i]+i]--; for(int i = R; i <= r; i++) sumR[mi[i]+i]--; for(int i = mid+1; i <= r; i++) sum[mi[i]+i]--; } dc(l,mid); dc(mid+1, r); } void main() { n = read(); for(int i = 1, j; i <= n; i++) j = read(), a[j] = read(); dc(1,n); printf("%lld\n",ans); }}int main(){ runzhe2000::main();}
0 0
- 51nod-1555:布丁怪
- 51Nod 1555 布丁怪
- [分治] 51Nod1555 布丁怪
- [51nod1555][CF526F]布丁怪
- 51Nod
- 51Nod
- 51nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod 1608 管道安装
- JavaScript学习笔记_2_函数Basic
- Python format 笔记
- 模块导入的方式
- BZOJ 4553 [Tjoi2016&Heoi2016]序列
- 51Nod 1555 布丁怪
- Educational Codeforces Round 18 C. Divide by Three
- github关联Unreal Engine 4源码教程2017.04.02
- javascript找到数组中最大值
- vim中批量修改数字(加减)
- 菜单--->子菜单
- HDU 6007 Mr. Panda and Crystal (最短路 + 完全背包)
- 修改VMwarede ubuntu的DNS
- 练习 打开文件&保存文件