洛谷题面传送门

一个线性做法。

\(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 的新生舞会 的线性做法的更多相关文章

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

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

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

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

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

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

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

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

  5. [题解] [Code+#1]Yazid 的新生舞会

    题面 题解 upd : \(cnt_i\) 代表值为 \(i\) 的个数 我们可以暴力枚举众数 \(k\) 把等于 \(k\) 的赋值成 1 , 不等于 \(k\) 的赋值成 -1 这样原序列就变成了 ...

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

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

  7. BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)

    LOJ BZOJ 洛谷 又来发良心题解啦 \(Description\) 给定一个序列\(A_i\).求有多少个子区间,满足该区间众数出现次数大于区间长度的一半. \(n\leq5\times10^5 ...

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

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

  9. 洛谷UVA12995 Farey Sequence(欧拉函数,线性筛)

    洛谷题目传送门 分数其实就是一个幌子,实际上就是求互质数对的个数(除开一个特例\((1,1)\)).因为保证了\(a<b\),所以我们把要求的东西拆开看,不就是\(\sum_{i=2}^n\ph ...

随机推荐

  1. Pycharm无法打开,双击没反应

    以下方案皆为引用,仅供参考. 方案一: 1.先声明一下,这种解决方法适用于任何版本的永久破解启动不了的情况(包括:2019版本的)2.下面直接切入正题之所以我们破解之后,不能正常启动的原因有两种:① ...

  2. javascript-jquery-更改jquery对象

    在许多情况下,jquery代码所做的事情变成了:生成jquery对象A,操作对jquery象A:更改为jquery对象B,操作jquery对象B:更改为jqueryC,操作jquery对象C..... ...

  3. 小白自制Linux开发板 七. USB驱动配置

    本文章基于https://whycan.com/t_3087.htmlhttps://whycan.com/t_6021.html整理 F1c100s芯片支持USB的OTG模式,也就是可以通过更改Us ...

  4. BUAA软工-结对项目作业

    结对项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 通过这门课锻炼软件开发能力和经验,强化与他人合作 ...

  5. 【BZOJ 1419】Red is good [概率DP]

    我 是 Z Z 概率好玄啊(好吧是我太弱.jpg Description 桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元.可以随时停止翻 ...

  6. 计算机网络之网络层移动IP

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105319753 学习课程:<2019王道考研计算机网络> 学习目的 ...

  7. 今天学习了BootStrap

    今天学习了BootStrap 一.BootStrap介绍 Bootstrap是一个前端开发的框架,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.Java ...

  8. Flink计算pv和uv的通用方法

    PV(访问量):即Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次. UV(独立访客):即Unique Visitor,访问您网站的一台电脑客户端为一个访客.00:00-24:00 ...

  9. 安装、卸载 node.js出错 Could not access network location *:\node.js\ 出错

    上周五,WIN10自动更新系统,导致我的node.js 和 Gradle 还有解压的winRAR都不能用!!!可恶 自动更新!!可恶啊!!! 然后我想把node.js重新卸载了再安装,结果 很慌很慌, ...

  10. 计算机网络漫谈之OSI七层模型和TCP/IP四层模型

    在 什么是网络? 中,你已经知道计算机网络是物理连接的"局域网"和工作于这个局域网上的"网络协议",并且我们的重心是网络协议.有关网络协议,按照目前的分层方式主 ...