[题解] [Code+#1]Yazid 的新生舞会
题面
题解
upd : \(cnt_i\) 代表值为 \(i\) 的个数
我们可以暴力枚举众数 \(k\)
把等于 \(k\) 的赋值成 1 , 不等于 \(k\) 的赋值成 -1
这样原序列就变成了一段折线

我们把他剖开一段一段来分析

这些蓝线的左右端点分别为, 一个值为众数的数的位置, 和它下一个值为众数的数的位置的前一个位置
为了方便, 我们定义 \(0\) , \(n + 1\) 这两个位置上的数可以当做任意一个位置
我们对于一条蓝线扯出来单独分析
设 \(sum_i\) 为折线在 \(i\) 这个点的值
只要我们找到两个点满足 \(i > j\) , 并且满足 \(sum_i > sum_j\) , 就有序列在 \([j + 1, i]\) 上的变化大于 0 , 也就是说是满足区间众数大于区间长度一半的
设它的值域为 \([l, r]\) , 暴力做法是这样的
对于 \(i \ in [l, r]\) , 将 \(\sum_{j = -\infty }^{i - 1} cnt_j\) 加入答案贡献
把 \(cnt_i\) 加一
考虑优化这个过程
\begin{aligned}
ans &= \sum_{i = l}^r\sum_{j=-\infty}^{i - 1}cnt_i\\
&= (r - l + 1) \sum_{j = -\infty}^{l - 1}cnt_i + \sum_{i = l}^{r - 1}(r - i)*cnt_i\\
&= (r - l + 1) \sum_{j = -\infty}^{l - 1}cnt_i + r * \sum_{i = l} ^ {r - 1}cnt_i - \sum_{i = l} ^ {r - 1}i * cnt_i
\end{aligned}
\]
所以我们在线段树上维护 \(cnt_i\) 和 \(i * cnt_i\) 即可
然后像上面那样每一个蓝色的线都这么分析
对于一个众数 \(k\) 它的复杂度为 \(O(mlogn)\) , \(m\) 为 \(a\) 中等于 \(k\) 的数的个数
所以总的复杂度就是 \(O(nlogn)\)
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
typedef long long ll;
const int N = 500005;
using namespace std;
int n, m, a[N];
struct Tree { ll sum[2], tag; } t[N << 4];
vector <int> vec[N];
ll ans;
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
void update(int p)
{
t[p].sum[0] = t[p << 1].sum[0] + t[p << 1 | 1].sum[0];
t[p].sum[1] = t[p << 1].sum[1] + t[p << 1 | 1].sum[1];
}
void pushdown(int p, int l, int r)
{
if(t[p].tag)
{
int ls = p << 1, rs = ls | 1, mid = (l + r) >> 1;
t[ls].sum[0] += 1ll * t[p].tag * (mid - l + 1), t[ls].tag += t[p].tag;
t[ls].sum[1] += 1ll * t[p].tag * (mid + l - m) * (mid - l + 1) / 2;
t[rs].sum[0] += 1ll * t[p].tag * (r - mid), t[rs].tag += t[p].tag;
t[rs].sum[1] += 1ll * t[p].tag * (mid + r + 1 - m) * (r - mid) / 2;
t[p].tag = 0;
}
}
void modify(int p, int l, int r, int ql, int qr, int k)
{
if(l > r || ql > qr) return;
if(ql <= l && r <= qr)
{
t[p].tag += k;
t[p].sum[0] += (r - l + 1) * k;
t[p].sum[1] += 1ll * (l + r - m) * (r - l + 1) / 2 * k;
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if(ql <= mid) modify(p << 1, l, mid, ql, qr, k);
if(mid < qr) modify(p << 1 | 1, mid + 1, r, ql, qr, k);
update(p);
}
ll query(int p, int l, int r, int ql, int qr, int op, int opt = 1)
{
if(l > r || ql > qr) return 0;
if(ql <= l && r <= qr)
return t[p].sum[op];
pushdown(p, l, r);
int mid = (l + r) >> 1; ll res = 0;
if(ql <= mid) res = query(p << 1, l, mid, ql, qr, op, opt);
if(mid < qr) res = res + query(p << 1 | 1, mid + 1, r, ql, qr, op, opt);
update(p);
return res;
}
int main()
{
n = read <int> (), read <int> ();
m = n << 1;
for(int i = 1; i <= n; i++)
{
a[i] = read <int> ();
vec[a[i]].push_back(i);
}
for(int i = 0; i < n; i++)
vec[i].push_back(n + 1);
for(int sz, st, ed, i = 0; i < n; i++)
{
sz = vec[i].size();
if(sz == 1) continue;
st = 0;
for(int j = 0; j < sz; j++)
{
ed = 2 * j + 1 - vec[i][j];
ans += 1ll * (st - ed + 1) * query(1, 1, m, 1, ed - 1 + n, 0)
+ st * query(1, 1, m, ed + n, st - 1 + n, 0)
- query(1, 1, m, ed + n, st - 1 + n, 1);
modify(1, 1, m, ed + n, st + n, 1);
st = ed + 1;
}
st = 0;
for(int j = 0; j < sz; j++)
{
ed = 2 * j + 1 - vec[i][j];
modify(1, 1, m, ed + n, st + n, -1);
st = ed + 1;
}
}
printf("%lld\n", ans);
return 0;
}
[题解] [Code+#1]Yazid 的新生舞会的更多相关文章
- 【线段树】【P4062】 [Code+#1]Yazid 的新生舞会
Description 给定一个长度为 \(n\) 的序列,求有多少子区间满足区间众数严格大于区间长度的一半.如果区间有多个出现次数最多且不同的数则取较小的数为众数. Limitation 对于全部的 ...
- P4062 [Code+#1]Yazid 的新生舞会
思路:分治 提交:2次 错因:数组开小 题解: 我们枚举一下众数\(x\). 设\(s[n]=\sum_{i=1}^n [a[i]==x]\) 那么对于区间\((l,r]\),有\(s[r]-s[l] ...
- luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)
今天原来是平安夜啊 感觉这题是道好题. 一个套路枚举权值\(x\),把权值等于\(x\)的设为1,不等于的设为-1,然后问题转化为多少个区间权值和大于. 发现并不是很好做,还有一个套路,用前缀和查分来 ...
- 洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法
洛谷题面传送门 一个线性做法. \(n\log n\) 解法可以戳这里查看 首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t ...
- 洛谷 P4062 - [Code+#1]Yazid 的新生舞会(权值线段树)
题面传送门 题意: 给出一个序列 \(a\),求 \(a\) 有多少个子区间 \([l,r]\),满足这个区间中出现次数最多的数出现次数 \(>\dfrac{r-l+1}{2}\) \(1 \l ...
- 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树
[BZOJ5110][CodePlus2017]Yazid 的新生舞会 Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一 ...
- [loj 6253] Yazid的新生舞会
(很久之前刷的题现在看起来十分陌生a) 题意: 给你一个长度为n的序列A,定义一个区间$[l,r]$是“新生舞会的”当且仅当该区间的众数次数严格大于$\frac{r-l+1}{2}$,求有多少子区间是 ...
- bzoj5110: [CodePlus2017]Yazid 的新生舞会
Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- 【bzoj5110】Yazid的新生舞会
这里是 $THUWC$ 选拔时间 模拟赛的时候犯 $SB$ 了,写了所有的部分分,然后直接跑过了 $4$ 个大样例(一个大样例是一个特殊情况)…… 我还以为我非常叼,部分分都写对了,于是就不管了…… ...
随机推荐
- 【php socket通讯】php实现http服务
http服务是建立在tcp服务之上的,它是tcp/ip协议的应用,前面我们已经实现了tcp服务,并且使用三种不同的方式连接tcp服务 php中连接tcp服务的三种方式 既然http也是tcp应用层的一 ...
- vue去哪儿网项目环境配置
一.首先安装node.js 根据自己的(windows或mac)系统进行安装node,在开发环境中一般安装LTS版本.安装成功后,在终端输入"node -v"和"npm ...
- 彻底弄懂HTTP缓存机制及原理-转载
首先附上原文地址,非常感谢博主大神的分享彻底弄懂HTTP缓存机制及原理 前言 Http 缓存机制作为 web 性能优化的重要手段,对于从事 Web 开发的同学们来说,应该是知识体系库中的一个基 ...
- docker的学习2
docker基本命令: run 创建一个新的容器并运行一个新的命令 -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项: -d: 后台运行容器,并返回容器 ...
- Computer Vision_33_SIFT:Evaluation of Interest Point Detectors——2000
此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...
- Ubuntu系统---报错Assertion '0' failed
Ubuntu系统---报错Assertion '0' failed YOLO V3,CUDA Error: out of memory darknet: ./src/cuda.c:36: check_ ...
- php中unserialize 返回false的解决方法
serialize 序列化 unserialize 反序列化 $content = 'a:5:{s:4:"img1";s:5:"35568";s:4:" ...
- es相关
1.es在数据量很大的情况下(数十亿级别)如何提高查询性能啊? 2.es生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片? 3.es的分布式架构原理能说一下么(es是如何 ...
- ajax 页面无刷新
<!-- 使用原生Ajax 和 $.ajax 实现局部刷新的过程 --><!-- 封装通用XMLHttpRequest对象 --><!DOCTYPE html>&l ...
- 3、python--第三天练习题
#1.简述普通参数.指定参数.默认参数.动态参数的区别 #1.普通参数就是传入的函数,没有默认值 def f(a): a = a + 1 return a print(f(3)) #2.指定参数 de ...