题面

题解

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\) 加一

考虑优化这个过程

\[\displaystyle
\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 的新生舞会的更多相关文章

  1. 【线段树】【P4062】 [Code+#1]Yazid 的新生舞会

    Description 给定一个长度为 \(n\) 的序列,求有多少子区间满足区间众数严格大于区间长度的一半.如果区间有多个出现次数最多且不同的数则取较小的数为众数. Limitation 对于全部的 ...

  2. P4062 [Code+#1]Yazid 的新生舞会

    思路:分治 提交:2次 错因:数组开小 题解: 我们枚举一下众数\(x\). 设\(s[n]=\sum_{i=1}^n [a[i]==x]\) 那么对于区间\((l,r]\),有\(s[r]-s[l] ...

  3. luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)

    今天原来是平安夜啊 感觉这题是道好题. 一个套路枚举权值\(x\),把权值等于\(x\)的设为1,不等于的设为-1,然后问题转化为多少个区间权值和大于. 发现并不是很好做,还有一个套路,用前缀和查分来 ...

  4. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法

    洛谷题面传送门 一个线性做法. \(n\log n\) 解法可以戳这里查看 首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t ...

  5. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会(权值线段树)

    题面传送门 题意: 给出一个序列 \(a\),求 \(a\) 有多少个子区间 \([l,r]\),满足这个区间中出现次数最多的数出现次数 \(>\dfrac{r-l+1}{2}\) \(1 \l ...

  6. 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树

    [BZOJ5110][CodePlus2017]Yazid 的新生舞会 Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一 ...

  7. [loj 6253] Yazid的新生舞会

    (很久之前刷的题现在看起来十分陌生a) 题意: 给你一个长度为n的序列A,定义一个区间$[l,r]$是“新生舞会的”当且仅当该区间的众数次数严格大于$\frac{r-l+1}{2}$,求有多少子区间是 ...

  8. bzoj5110: [CodePlus2017]Yazid 的新生舞会

    Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...

  9. 【bzoj5110】Yazid的新生舞会

    这里是 $THUWC$ 选拔时间 模拟赛的时候犯 $SB$ 了,写了所有的部分分,然后直接跑过了 $4$ 个大样例(一个大样例是一个特殊情况)…… 我还以为我非常叼,部分分都写对了,于是就不管了…… ...

随机推荐

  1. .net core mvc + mysql dbfirst 生成 ado.net 数据模型

    1.点击“工具”->“NuGet包管理器”->“程序包管理器控制台” 安装一下包 Install-Package MySql.Data.EntityFrameworkCore -Pre I ...

  2. vue中用div的contenteditable属性实现v-for遍历,双向数据绑定的动态表格编辑

    1.HTML部分 <tr v-for="(item,index) in customerVisitList2" :key="index"> < ...

  3. Grassfire算法- 运动规划(Motion planning)

     Grassfire算法: 一.概念 这个算法是做图像处理的抽骨架处理,目的是求出图像的骨架,可以想象一片与物体形状相同的草,沿其外围各点同时点火.当火势向内蔓延,向前推进的火线相遇处各点的轨迹就是中 ...

  4. POST,PUT和PATCH的区别

    1. GET方法用于获取资源,不应有副作用,所以是幂等的. 比如:GET http://www.bank.com/account/123456,不会改变资源的状态,不论调用一次还是N次都没有副作用.请 ...

  5. docker在Windows环境下的安装

    Windows环境下安装 docker有两种安装包 一.Docker for Windows(目前只能在 64 位的 Windows10 专业版.企业版.教育版下才能安装) 二.Docker Tool ...

  6. 使用C#的Flags特性

    举个例子:我有如下的一个需求,当我想要取得用户信息的时候,会先从本地缓存中查找,找不到然后从分布式缓存中查找,最后找不到再从数据库中查询.但是有些场景我又不需要查询数据库. 所以我想建立如下这种模型. ...

  7. 洛谷P5002 专心OI - 找祖先

    题目概括 题目描述 这个游戏会给出你一棵树,这棵树有\(N\)个节点,根结点是\(R\),系统会选中\(M\)个点\(P_1,P_2...P_M\). 要Imakf回答有多少组点对\((u_i,v_i ...

  8. ZZNU-OJ-2098 : Drink coffee【线段树合并区间或者 差分 + 二分索引树】

    : Drink coffee 时间限制: Sec 内存限制: MiB 提交: 答案正确: 提交 状态 讨论区 题目描述 为了在上课时保持清醒,凯伦需要一些咖啡.咖啡爱好者凯伦想知道最佳的温度来冲煮完美 ...

  9. 2018/7/31-zznu-oj- 2128: 素数检测 -【费马小定理裸应用】

    2128: 素数检测 时间限制: 1 Sec  内存限制: 128 MB提交: 84  解决: 32[提交] [状态] [讨论版] [命题人:admin] 题目描述 在算法竞赛中你会遇到各种各样的有关 ...

  10. ubuntu下后台服务的管理

    注册后台服务后都有脚本存在/lib/systemd/system路径下 如mysql为mysql.service 被service管理的进程被杀掉还是会重启的 应使用service XXX stop停 ...