牛客多校第三场 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. 为什么printf()用%f输出double型,而scanf却用%lf呢?

    之前没有注意过这个问题,  转自: http://book.51cto.com/art/200901/106880.htm 问:有人告诉我不能在printf中使用%lf.为什么printf()用%f输 ...

  2. CVE-2019-0708漏洞利用

    20190514,微软发布补丁,修复了一个严重的RDP远程代码执行漏洞.该漏洞无需身份认证和用户交互,可能形成蠕虫爆发,影响堪比wannycry. 影响范围: Windows 7 Windows Se ...

  3. vim删除行

    0,vim filename 1,显示行号 :set number 2,跳转到第1000行 1000G (跳转到文件末尾:“G”) 3,删除1-1000行 :1,.d 4,删除所有行 先跳转到文件最后 ...

  4. wepy ——$apply

    1.说明 在异步函数中更新数据的时候,必须手动调用 $apply 方法. 2.代码和效果 // html <button type="primary" plain=" ...

  5. 19-3 auth模块

    参考:https://www.cnblogs.com/liwenzhou/p/9030211.html 一 auth使用django默认的user表 1 auth常用方法 1. authenticat ...

  6. jQuery仿迅雷图片轮换效果

    jQuery仿迅雷图片轮换效果 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  7. oracle总是使用索引的第一个列

    如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引. 译者按: 这也是一条简单而重要的规则. 见以下实例. SQL> ...

  8. HDU1358 Period 题解 KMP算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358 题目大意:给你一个长度为 \(n\) 的字符串 \(s\) ,那么它有 \(n\) 个前缀. 对 ...

  9. Python--day72--ajax简介

    ajax的基本结构: <script> $("#b1").on("click", function () { $.ajax({ url: " ...

  10. 洛谷P2258 子矩阵 题解 状态压缩/枚举/动态规划

    作者:zifeiy 标签:状态压缩.枚举.动态规划 题目链接:https://www.luogu.org/problem/P2258 这道题目状态压缩是肯定的,我们需要用二进制来枚举状态. 江湖上有一 ...