[LOJ 6253] Yazid 的新生舞会
$solution:$
不知道为什么别人的代码能写的非常短,难道就是写差分的好处?
这种题肯定是算每个众数的贡献,考虑通过暴力众数求出个数。
现在考虑众数 $x$ ,则在序列 $a$ 中将等于 $x$ 的置为 $1$ ,否则置为 $-1$,令为序列 $A$ 。设 $S_i=\sum_{k=1}^i A_k$。
若 $[l,r]$ 是满足题意的区间,则 $S_r>S_{l-1}$ ,所以对于每个众数 $x$ ,求出满足 $i>j,S_i>S_j$ 的方案数,直接求二维偏序即可,时间复杂度 $O(n^2\log n)$ ,并不能通过本题。
但是,我们能发现一个性质,在每个 $A$ 中只会有很少的 $1$ ,与很多的 $-1$ 出现,因为 $1$ 只能在 $A$ 中出现 $n$ 次。对于连续 $-1$ 段来说不可能 $l,r$ 均在其中,并且它们的 $S$ 值是每次减一,所以考虑将它们合为一个,其 $S$ 的范围为 $[L,R]$ ,可以简单发现连续段个数与 $n$ 同阶。
考虑将 $-1$ 连续段中作为右端点对答案的贡献,设 $l,r$ 为连续段的左右端点,$L,R$ 为 $S$ 的范围,$C_i$ 为满足 $S_k=i,k\in [0,i)$ 的个数。
则容易推出$$Ans=\sum_{i=-n}^{L-1} C_i\times (R-L+1)+\sum_{i=L}^R C_i\times (R-i)\\=\sum_{i=-n}^{L-1} C_i\times (R-L+1)+\sum_{i=L}^R C_i-\sum_{i=L}^R C_i\times i$$
发现 $\sum_{i=-n}^{L-1} C_i\times (R-L+1)$ 这两个式子直接线段树区间加法维护即可,而 $\sum_{i=L}^R C_i\times i$ 直接线段树上维护等差数列即可。
现在考虑完右端点在 $-1$ 的情况,而右端点在 $1$ 时直接线段树查询 $[-n,S_{i}-1]$ 即可。
因为区间段与 $n$ 同阶,所以时间复杂度为 $O(n\log n)$ 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
int n,a[MAXN];
vector<int> ve[MAXN];
struct Segment1{
int Ans[MAXN<<],Beg[MAXN<<],D[MAXN<<],qx[MAXN],qy[MAXN],qbe[MAXN],qd[MAXN],tot;
inline void clear(){
for(int i=;i<=tot;i++) Modify(,,*n,qx[i],qy[i],-qbe[i],-qd[i]);
tot=;
}
inline void pushdown(int k,int l,int r){
int mid=l+r>>;
if(!Beg[k]&&!D[k]) return;
Ans[k<<]+=Beg[k]*(mid-l+)+((((mid-l+)*(mid-l))/)*D[k]);
Ans[k<<|]+=Beg[k]*(r-mid)+((((r+mid-*l+)*(r-mid))/)*D[k]);
Beg[k<<]+=Beg[k],Beg[k<<|]+=Beg[k]+(mid+-l)*D[k];
D[k<<]+=D[k],D[k<<|]+=D[k];
Beg[k]=D[k]=;
return;
}
inline void Modify(int k,int l,int r,int x,int y,int be,int d){
if(x<=l&&r<=y){
Ans[k]+=((r-l+)*be)+(((((l+r)*(r-l+))/)-(x*(r-l+)))*d);
Beg[k]+=(be+(l-x)*d);
D[k]+=d;
return;
}
pushdown(k,l,r);
int mid=l+r>>;
if(x<=mid) Modify(k<<,l,mid,x,y,be,d);
if(mid<y) Modify(k<<|,mid+,r,x,y,be,d);
Ans[k]=Ans[k<<]+Ans[k<<|];
return;
}
inline int Query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return Ans[k];
pushdown(k,l,r);
int mid=l+r>>,res=;
if(x<=mid) res+=Query(k<<,l,mid,x,y);
if(mid<y) res+=Query(k<<|,mid+,r,x,y);
Ans[k]=Ans[k<<]+Ans[k<<|];return res;
}
inline void add(int x,int y,int be,int d){
qx[++tot]=x+n;qy[tot]=y+n;qbe[tot]=be,qd[tot]=d;
Modify(,,*n,x+n,y+n,be,d);return;
}
inline int Q(int x,int y){
return Query(,,*n,x+n,y+n);
}
}segment1;
struct Segment2{
int Ans[MAXN<<],tag[MAXN<<];
int qx[MAXN],qy[MAXN],qw[MAXN],tot;
inline void clear(){
for(int i=;i<=tot;i++) Modify(,,*n,qx[i],qy[i],-qw[i]);
tot=;
}
inline void pushdown(int k,int l,int r){
if(!tag[k]) return;
int mid=l+r>>;
Ans[k<<]+=tag[k]*(mid-l+);Ans[k<<|]+=tag[k]*(r-mid);
tag[k<<]+=tag[k],tag[k<<|]+=tag[k];
tag[k]=;return;
}
inline void Modify(int k,int l,int r,int x,int y,int w){
if(x<=l&&r<=y){
tag[k]+=w;
Ans[k]+=(r-l+)*w;return;
}
pushdown(k,l,r);
int mid=l+r>>;
if(x<=mid) Modify(k<<,l,mid,x,y,w);
if(mid<y) Modify(k<<|,mid+,r,x,y,w);
Ans[k]=Ans[k<<]+Ans[k<<|];return;
}
inline int Query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return Ans[k];
pushdown(k,l,r);
int mid=l+r>>,res=;
if(x<=mid) res+=Query(k<<,l,mid,x,y);
if(mid<y) res+=Query(k<<|,mid+,r,x,y);
Ans[k]=Ans[k<<]+Ans[k<<|];return res;
}
inline void add(int x,int y,int w){
qx[++tot]=x+n,qy[tot]=y+n,qw[tot]=w;
Modify(,,*n,x+n,y+n,w);return;
}
inline int Q(int x,int y){
return Query(,,*n,x+n,y+n);
}
}segment2;
int Ans;
signed main(){
// freopen("1.in","r",stdin);
n=read();read();
for(int i=;i<=n;i++) a[i]=read(),ve[a[i]].push_back(i);
for(int i=;i<n;i++){
int siz=ve[i].size();
if(!siz) continue;
int l=,r=-;
segment1.clear();
segment2.clear();
segment1.add(,,,);
segment2.add(,,);
for(int j=;j<siz;j++){
int u=ve[i][j];
r=u-;
if(j!=) l=ve[i][j-]+;
else l=;
if(l<=r){
int L=-l+j*,R=-r+j*;
if(L>R) swap(L,R);
Ans+=segment2.Q(-n,L-)*(R-L+);
Ans+=R*segment2.Q(L,R);
Ans-=segment1.Q(L,R);
segment1.add(L,R,L,);
segment2.add(L,R,);
}
int Psum=-u+*(j+);
Ans+=segment2.Q(-n,Psum-);
segment1.add(Psum,Psum,Psum,);
segment2.add(Psum,Psum,);
}
l=ve[i][siz-]+,r=n;
if(l<=r){
int L=-l+siz*,R=-r+siz*;
if(L>R) swap(L,R);
Ans+=segment2.Q(-n,L-)*(R-L+);
Ans+=R*segment2.Q(L,R);;
Ans-=segment1.Q(L,R);
segment1.add(L,R,L,);
segment2.add(L,R,);
}
}printf("%lld\n",Ans);return ;
}
[LOJ 6253] Yazid 的新生舞会的更多相关文章
- [loj 6253] Yazid的新生舞会
(很久之前刷的题现在看起来十分陌生a) 题意: 给你一个长度为n的序列A,定义一个区间$[l,r]$是“新生舞会的”当且仅当该区间的众数次数严格大于$\frac{r-l+1}{2}$,求有多少子区间是 ...
- 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树
[BZOJ5110][CodePlus2017]Yazid 的新生舞会 Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一 ...
- bzoj5110: [CodePlus2017]Yazid 的新生舞会
Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- 【bzoj5110】Yazid的新生舞会
这里是 $THUWC$ 选拔时间 模拟赛的时候犯 $SB$ 了,写了所有的部分分,然后直接跑过了 $4$ 个大样例(一个大样例是一个特殊情况)…… 我还以为我非常叼,部分分都写对了,于是就不管了…… ...
- BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)
LOJ BZOJ 洛谷 又来发良心题解啦 \(Description\) 给定一个序列\(A_i\).求有多少个子区间,满足该区间众数出现次数大于区间长度的一半. \(n\leq5\times10^5 ...
- 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会
题解: 没笔的时候我想了一下 发现如果不是出现一半次数而是k次,并不太会做 然后我用前缀和写了一下发现就是维护一个不等式: 于是就可以随便维护了
- 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)
学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...
- 【bzoj5110】[CodePlus2017]Yazid 的新生舞会 Treap
题目描述 求一个序列所有的子区间,满足区间众数的出现次数大于区间长度的一半. 输入 第一行2个用空格隔开的非负整数n,type,表示序列的长度和数据类型.数据类型的作用将在子任务中说明. 第二行n个用 ...
- [BZOJ5110]Yazid的新生舞会
题目大意: 给你一个长度为$n(n\leq 5\times 10^5)$的序列$A_{1\sim n}$.求满足区间众数在区间内出现次数严格大于$\lfloor\frac{r-l+1}{2}\rflo ...
随机推荐
- 【方法】原生js实现方法ajax封装
/* 参数说明* type[String] 请求方式('POST'或'GET') 默认设置'GET'方式* dataType[String] 获取到的后台数据格式 默认'JSON'格式* async[ ...
- SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)
题意 : 给出一段n个数的序列,接下来给出m个询问,询问的内容SPOJ是(L, R)这个区间内不同的数的个数,HDU是不同数的和 分析 : 一个经典的问题,思路是将所有问询区间存起来,然后按右端点排序 ...
- CDOJ 1069 秋实大哥去打工 单调栈 下标处理
E - 秋实大哥去打工 Time Limit:1000MS Memory Limit:65535KB 64bit IO Format:%lld & %llu Submit St ...
- 2-gitblit添加项目,项目成员
创建代码仓库,如下图所示, 然后填个项目的名称和描述即可点击保存. 用户也是,还是相同的位置,点击用户,而不是用户中心,创建用户也是填写用户名称和简称,最后对在旁边有个用户的权限,选择相应的代码仓库即 ...
- 基于数组阻塞队列 ArrayBlockingQueue 的一个队列工具类
java语言基于ArrayBlockingQueue 开发的一个根据特定前缀和后缀的队列.每天自动循环生成. 1.定义队列基类 Cookie package com.bytter.util.queue ...
- Hbase数据备份&&容灾方案
Hbase数据备份&&容灾方案 标签(空格分隔): Hbase 一.Distcp 在使用distcp命令copy hdfs文件的方式实现备份时,需要禁用备份表确保copy时该表没有数据 ...
- 简单实现骨架屏 (Skeleton Screens)
近年,国内外各大网站都引入骨架屏(Skeleton Screens)技术来提高用户体验.相比于之前的Loading动画,骨架屏页面更容易让用户产生一种错觉,页面快加载完了.骨架屏实现原理很 ...
- Centos7系统备份与恢复教程
原文地址:https://www.cnblogs.com/fang888/p/8473485.html Centos系统备份与恢复教程 tar: 特点 1.保留权限 2.适合备份整个目录 3.可以选择 ...
- 微信 JS-SDK 各种问题记录
在开发微信公众号网页中,使用微信的 JS-SDK 会遇到各种坑.记录遇到的坑及解决方法. 1.JS-SDK 配置(url 指向). 在 JS-SDK 配置中,配置的签名基本在服务器完成,网上有各种方法 ...
- C#的keyValue