洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法
一个线性做法。
\(n\log n\) 解法可以戳这里查看
首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t_3,\cdots,t_c\),然后在这些位置上填上 \(1\),其余位置上填上 \(-1\),然后对序列做一遍前缀和,那么该数对答案的贡献就是前缀和数组中顺序对个数。
直接 \(n\log n\) 求复杂度好像有一点高,怎样优化复杂度呢?首先注意到每个可能成为区间右端点的位置并不多,具体来说,我们猜测它是 \(\mathcal O(c)\) 级别的,其中 \(c\) 为 \(x\) 在原序列中的出现次数,也就是说,我们称前缀和数组为 \(s_k\),那么满足 \(s_k>\min\limits_{j=1}^{k-1}s_j\) 的 \(k\) 的总个数是线性的,因此我们考虑每次计算一个连续递减段的贡献时,暴力向后枚举,直到 \(s_k\le\min\limits_{j=1}^{k-1}s_j\) 即可,这样我们只用实现区间加区间求和(求前缀和),即二阶差分数组上单点加,求二阶差分数组的二阶前缀和即可。
到这里,直接做的复杂度还是带 log 的。我们还能注意到这样一个事实:\(s\) 数组中相邻两个元素之差为 \(\pm 1\)。因此我们考虑动态维护一个指针 \(p\),并动态维护二阶差分数组在 \((-\infty...p-1]\) 处的一阶、二阶前缀和,这样向上移动指针时就加入当前位置的贡献,否则扣除掉当前位置的贡献,这样就不用 BIT 之类的东西维护前缀和。直接移动指针显然会被卡到平方,不过发现对于一段连续递减段,我们假设暴力向后枚举到的位置为 \(q\),那么由于对于 \(q+1\) 到该连续段右端点 \(r\) 这段区间内任意一个 \(k\),都有 \(s_k>\min\limits_{j=1}^{k-1}s_j\),因此这部分的位置在移动指针的过程中肯定是空的,直接一路移下去不加任何贡献即可。这样需要加贡献的部分就是待查询的部分,外加上 \(x\) 的 \(c\) 个出现位置 \(t_1,t_2,t_3,\cdots,t_c\),总个数是 \(\Theta(c)\) 级别的,因此总复杂度就是 \(\Theta(\sum c)=\Theta(n)\)。
话说这题我好像已经写了四种不同复杂度/不同常数的做法了?\(n\sqrt{n\log n}\) 分块,\(n\log n\) 线段树,\(n\log n\) BIT,\(\mathcal O(n)\) 指针维护。看来此题确实是一道很值得研究的题目。
代码(目前洛谷最优解,335ms):
using namespace fastio;
const int MAXN=5e5;
const int DLT=MAXN+3;
int n,fuck,a[MAXN+5],hd[MAXN+5],val[MAXN+5],nxt[MAXN+5],item_n=0;
void ins(int x,int y){val[++item_n]=y;nxt[item_n]=hd[x];hd[x]=item_n;}
int d[MAXN*2+10];
inline void add(int l,int r,int v){d[l+DLT]+=v;d[r+DLT+1]-=v;}
int main(){
read(n);read(fuck);add(0,0,1);ll res=0;
for(int i=1;i<=n;i++) read(a[i]),ins(a[i],i);
for(int v=0;v<n;v++) if(hd[v]){
static int pos[MAXN+5],sum[MAXN+5];int cnt=-1;
pos[++cnt]=n+1;
for(int e=hd[v];e;e=nxt[e]) pos[++cnt]=val[e];
pos[++cnt]=0;reverse(pos,pos+cnt+1);sum[0]=0;
if(cnt==2){res++;continue;}
int mnp=0;ll sum1=0,sum2=0;
for(int i=1;i<=cnt;i++){
int l=sum[i-1]-(pos[i]-pos[i-1]-1),r=sum[i-1]-1;
if(l<=r){
int lim=max(l,mnp);
for(int j=r;j>=lim;j--){
sum2-=sum1;sum1-=d[j+DLT];
res+=sum2;
}
} if(i==cnt) break;
add(l,r,1);sum1+=d[l+DLT];sum2+=sum1;
sum[i]=l+1;add(sum[i],sum[i],1);res+=sum2;
chkmin(mnp,l);
}
for(int i=1;i<cnt;i++) add(sum[i]-1,sum[i-1]-1,-1),add(sum[i],sum[i],-1);
} printf("%lld\n",res);
return 0;
}
洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法的更多相关文章
- 洛谷 P4062 - [Code+#1]Yazid 的新生舞会(权值线段树)
题面传送门 题意: 给出一个序列 \(a\),求 \(a\) 有多少个子区间 \([l,r]\),满足这个区间中出现次数最多的数出现次数 \(>\dfrac{r-l+1}{2}\) \(1 \l ...
- luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)
今天原来是平安夜啊 感觉这题是道好题. 一个套路枚举权值\(x\),把权值等于\(x\)的设为1,不等于的设为-1,然后问题转化为多少个区间权值和大于. 发现并不是很好做,还有一个套路,用前缀和查分来 ...
- P4062 [Code+#1]Yazid 的新生舞会
思路:分治 提交:2次 错因:数组开小 题解: 我们枚举一下众数\(x\). 设\(s[n]=\sum_{i=1}^n [a[i]==x]\) 那么对于区间\((l,r]\),有\(s[r]-s[l] ...
- 【线段树】【P4062】 [Code+#1]Yazid 的新生舞会
Description 给定一个长度为 \(n\) 的序列,求有多少子区间满足区间众数严格大于区间长度的一半.如果区间有多个出现次数最多且不同的数则取较小的数为众数. Limitation 对于全部的 ...
- [题解] [Code+#1]Yazid 的新生舞会
题面 题解 upd : \(cnt_i\) 代表值为 \(i\) 的个数 我们可以暴力枚举众数 \(k\) 把等于 \(k\) 的赋值成 1 , 不等于 \(k\) 的赋值成 -1 这样原序列就变成了 ...
- 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树
[BZOJ5110][CodePlus2017]Yazid 的新生舞会 Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一 ...
- BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)
LOJ BZOJ 洛谷 又来发良心题解啦 \(Description\) 给定一个序列\(A_i\).求有多少个子区间,满足该区间众数出现次数大于区间长度的一半. \(n\leq5\times10^5 ...
- bzoj5110: [CodePlus2017]Yazid 的新生舞会
Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- 洛谷UVA12995 Farey Sequence(欧拉函数,线性筛)
洛谷题目传送门 分数其实就是一个幌子,实际上就是求互质数对的个数(除开一个特例\((1,1)\)).因为保证了\(a<b\),所以我们把要求的东西拆开看,不就是\(\sum_{i=2}^n\ph ...
随机推荐
- Mybatis 一级缓存 (20)
Mybatis中的一级缓存和二级缓存(本博文只是针对一级缓存说明) 概述 ORM框架一般都会有缓存机制,做为其中一员的Mybatis也存在缓存.功能是用以提升查询的效率和服务给数据库带来压力.同样的M ...
- python之字符串,列表,集合,字典方法
字典内置函数&方法 函数: 1.len(dict1):打印字典的键的个数 方法:dict1.( ) 2.clear():清空字典 3.copy():复制字典 4.fromkeys():使用指定 ...
- 四、Implementation: The Building Blocks 实现:构件
四.Implementation: The Building Blocks 实现:构件 This is the essential part of this guide. We will introd ...
- DOS命令和快捷键
- kviy TextInput 触发事件
from kivy.uix.widget import Widget from kivy.app import App from kivy.lang import Builder Builder.lo ...
- CodeForces-1076E Vasya and a Tree
CodeForces - 1076E Problem Description: Vasya has a tree consisting of n vertices with root in verte ...
- 从四个方向分析我们可以从linux学到什么
我们真正关心的是自身可以从这个生态圈中获得些什么?说得更直白一点就是,我们可以从linux系统上面学到点什么,它对我们个人的成长和发展有哪些积极的因素.个人觉得,完全可以通过下面四个维度并结合自己的兴 ...
- 『学了就忘』Linux基础 — 7、补充:安装Linxu系统时设置硬盘挂载说明
目录 (1)新建一个/home分区 (2)再创建一个/boot分区. (3)创建一个swap分区 (4)最后剩余的空间全部分给根目录 (5)总结 上一篇在VMwar虚拟机中安装Linux操作系统中ht ...
- createContext 你用对了吗?
目录 前言 性能问题的根源 问题1(整体重复渲染):Provider组件包裹的子组件全部渲染 问题2(局部重复渲染):使用useContext导致组件渲染 解决方案 解决问题1 解决问题2 参考 前言 ...
- 关于axios 的responseType类型的设置
responseType值的类型可为如下 axios请求下载导出一个文件,请求成功时返回的是一个流形式的文件,需要设置responseType: 'arraybuffer',但是请求失败的需要返回的是 ...