牛客多校第三场 G Removing Stones(分治+线段树)

题意:

给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半

题解:

分治+线段树

线段树维护最大值的位置,每次分治找就找这个最大值,然后看最大值在哪个序列是可行的

怎么看最大值所在的序列是否可行呢?

我们用一个前缀和维护区间和

\[max<=\frac{1}{2}(sum[r]-sum[l])\\
2*max-(sum[r]-sum[l])<=0\\
\]

这个最大值在这一段区间内都有可能出现

为了得到总的方案数

我们在当前区间内枚举靠近最大值出现的位置pos的那一段,然后二分右\左端点,即可得到一段最小的区间[i,t]或者[t,i]可以满足 区间内最大元素不大于所有元素和的一半的条件,然后计数就加上容斥后的r-t+1或者t-l+1这一段即可

代码:

/**
*        ┏┓    ┏┓
*        ┏┛┗━━━━━━━┛┗━━━┓
*        ┃       ┃  
*        ┃   ━    ┃
*        ┃ >   < ┃
*        ┃       ┃
*        ┃... ⌒ ...  ┃
*        ┃       ┃
*        ┗━┓   ┏━┛
*          ┃   ┃ Code is far away from bug with the animal protecting          
*          ┃   ┃ 神兽保佑,代码无bug
*          ┃   ┃           
*          ┃   ┃       
*          ┃   ┃
*          ┃   ┃           
*          ┃   ┗━━━┓
*          ┃       ┣┓
*          ┃       ┏┛
*          ┗┓┓┏━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 佛祖保佑 永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
double ans = 1.0;
while(b) {
if(b % 2)ans = ans * a;
a = a * a;
b /= 2;
} return ans;
}
LL quick_pow(LL x, LL y) {
LL ans = 1;
while(y) {
if(y & 1) {
ans = ans * x % mod;
} x = x * x % mod;
y >>= 1;
} return ans;
}
pii Max[maxn << 2]; LL sum[maxn];
int a[maxn];
void push_up(int rt) {
Max[rt] = max(Max[ls], Max[rs]);
}
void build(int l, int r, int rt) {
if(l == r) {
Max[rt] = make_pair(a[l], l);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt);
}
pii query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return Max[rt];
}
int mid = (l + r) >> 1;
pii ans = make_pair(0, 0);
if(L <= mid) ans = max(ans, query(L, R, lson));
if(R > mid) ans = max(ans, query(L, R, rson));
return ans;
}
//二分最短区间大于后缀
int find1(int l, int r, LL x) {
int L = l, R = r + 1, res = l - 1;
while (L <= R) {
int mid = (L + R) >> 1;
if (sum[r] - sum[mid - 1] >= x) {
L = mid + 1;
res = mid;
} else R = mid - 1;
}
return res;
}
int find2(int l, int r, LL x) {
int L = l - 1, R = r, res = r + 1;
while (L <= R) {
int mid = (L + R) >> 1;
if (sum[mid] - sum[l - 1] >= x) {
R = mid - 1;
res = mid;
} else L = mid + 1;
}
return res;
}
LL ans = 0;
int n;
void solve(int l, int r) {
if(l == r) return;
int mid = query(l, r, 1, n, 1).second; if(l < mid) solve(l, mid - 1);
if(r > mid) solve(mid + 1, r);
if(mid - l < r - mid) {
for(int i = l; i <= mid; i++) {
int t = find2(mid + 1, r, 2 * a[mid] - (sum[mid] - sum[i - 1]));
ans += r - t + 1;
}
} else {
for(int i = mid; i <= r; i++) {
int t = find1(l, mid - 1, 2 * a[mid] - (sum[i] - sum[mid - 1]));
ans += t - l + 1;
}
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int T;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
sum[0] = 0;
ans = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
build(1, n, 1);
solve(1, n);
printf("%lld\n", ans);
}
return 0;
}

牛客多校第三场 G Removing Stones(分治+线段树)的更多相关文章

  1. [2019牛客多校第三场][G. Removing Stones]

    题目链接:https://ac.nowcoder.com/acm/contest/883/G 题目大意:有\(n\)堆石头,每堆有\(a_i\)个,每次可以选其中两堆非零的石堆,各取走一个石子,当所有 ...

  2. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  3. 牛客多校第十场 A Rikka with Lowbit 线段树

    链接:https://www.nowcoder.com/acm/contest/148/A来源:牛客网 题目描述 Today, Rikka is going to learn how to use B ...

  4. 牛客多校第四场 J.Hash Function(线段树优化建图+拓扑排序)

    题目传送门:https://www.nowcoder.com/acm/contest/142/J 题意:给一个hash table,求出字典序最小的插入序列,或者判断不合法. 分析: eg.对于序列{ ...

  5. Removing Stones(2019年牛客多校第三场G+启发式分治)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 初始时有\(n\)堆石子,每堆石子的石子个数为\(a_i\),然后进行游戏. 游戏规则为你可以选择任意两堆石子,然后从这两堆中移除一个石子,最 ...

  6. 启发式分治:2019牛客多校第三场 G题 Removing Stones

    问题可以转换为求有多少个区间数字的总和除2向下取整大于等于最大值.或者解释为有多少个区间数字的总和大于等于最大值的两倍(但是若区间数字总和为奇数,需要算作减1) 启发式分治: 首先按最大值位置分治,遍 ...

  7. 牛客多校第三场 F Planting Trees

    牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...

  8. 牛客多校第四场 G Maximum Mode

    链接:https://www.nowcoder.com/acm/contest/142/G来源:牛客网 The mode of an integer sequence is the value tha ...

  9. 牛客多校第三场 A—pacm team (4维背包加路径压缩)

    链接:https://www.nowcoder.com/acm/contest/141/A 来源:牛客网 Eddy was a contestant participating , Eddy fail ...

随机推荐

  1. (五)IO流之ByteArrayInput/OutputStream

    ByteArrayInputStream:是把字节数组当成源的输入流 String string="hello shanghai"; ByteArrayInputStream bi ...

  2. hdu1532&&poj1273 最大流

    Dinic算法: 层次图:根据源点到该点的距离建图,这里设相邻的都差1. (下面部分转) 在这幅图中我们首先要增广1->2->4->6,这时可以获得一个容量为2的流,但是如果不建立4 ...

  3. hdu2149 巴什博奕

    n表示先手胜 p表示先手负 1~N N+1 N+2~2*N+1 2*N+2 2*N+3~3*N+2 ... n p n p n ... m总归个数 每次取1~N个根据前面的规律得到,如果m/N==m% ...

  4. React Native错误汇总(持续更新)

    错误1 Element type is invalid-: 错误描述: Element type is invalid: expected a String(for built-in componen ...

  5. 一 linux安装python3

    参考 https://www.cnblogs.com/pyyu/p/7402145.html?tdsourcetag=s_pcqq_aiomsg 1 下载 网址:https://www.python. ...

  6. Spring Security入门篇——标签sec:authorize的使用

    Security框架可以精确控制页面的一个按钮.链接,它在页面上权限的控制实际上是通过它提供的标签来做到的 Security共有三类标签authorize authentication accessc ...

  7. Java变量以及内存分配

    Java变量以及内存分配(非常重要) 堆栈 静态存储区域 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操 ...

  8. poj 1436 && zoj 1391 Horizontally Visible Segments (Segment Tree)

    ZOJ :: Problems :: Show Problem 1436 -- Horizontally Visible Segments 用线段树记录表面能被看见的线段的编号,然后覆盖的时候同时把能 ...

  9. 免费淘宝IP地址库简介及PHP/C#调用实例

    https://yq.aliyun.com/ziliao/25800?spm=a2c4e.11155472.0.0.68027abfcpFb7O 摘要: 本文讲的是免费淘宝IP地址库简介及PHP/C# ...

  10. 【原生JS】评论编辑器 文本操作

    效果图: HTML: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...