loj6253/luogu4062-Yazid的新生舞会
先考虑部分分(只有01/只有0~7)做法:枚举每个数,把和他相同的设为1,不同的设为-1,然后这个数作为众数贡献的个数就是区间和>0的个数
推着做,树状数组记前缀和<=x的区间的数量就可以,复杂度$O(8nlogn)$
如果直接套过来,$O(n^2logn)$肯定是不行的,但可以发现枚举了所有数以后1的个数一共只能有n个,而如果把相邻的-1看成一个,它的数量也是O(n)的
所以对于1的做法是不变的;对于-1,我们要连起来处理。如果设这段-1之前的和为sum,-1的个数为len可以得到这段-1的贡献,其实就是$[-n,sum-len-1]+[-n,sum-len]+...+[-n,sum-2]$(我们用一个权值线段树来记前缀和为某值的数量)
为了方便计算,做一个前缀和,就变成了
$$\sum\limits_{i=-n}^{sum-2}{\sum\limits_{j=-n}^{i}{a[j]}}-\sum\limits_{i=-n}^{sum-len-2}{\sum\limits_{j=-n}^{i}{a[j]}}$$
(可以看出与树状数组做区间加、区间求和的操作类似)
$$=(sum-2+1)\sum\limits_{i=-n}^{sum-2}{a[i]}-\sum\limits_{i=-n}^{sum-2}{i*a[i]}-((sum-len-2+1)\sum\limits_{i=-n}^{sum-len-2}{a[i]}-\sum\limits_{i=-n}^{sum-len-2}{i*a[i]})$$
然后用线段树维护a[i]和i*a[i]就可以了。而且我们每次枚举完一个以后不能直接memset,不然就变成O(n^2)了,要怎么加进来的就怎么减回去..
(然后我bzoj上就T了,肯定是评测机太卡了)
#define __Ressed__ <bits/stdc++.h>
#include __Ressed__
#define pa pair<int,int>
#define lowb(x) ((x)&(-(x)))
#define REP(i,n0,n) for(i=n0;i<=n;i++)
#define PER(i,n0,n) for(i=n;i>=n0;i--)
#define MAX(a,b) ((a>b)?a:b)
#define MIN(a,b) ((a<b)?a:b)
#define CLR(a,x) memset(a,x,sizeof(a))
#define rei register int
using namespace std;
typedef long long ll;
const int maxn=5e5+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} ll v[maxn*],iv[maxn*],laz[maxn*],ans;
int ch[maxn*][],pct,root;
int nxt[maxn],hd[maxn];
int L,N,M,num[maxn],tmp[maxn]; inline void pushdown(int p,int l,int r){
int m=l+r>>,a=ch[p][],b=ch[p][];
if(a){
laz[a]+=laz[p];
v[a]+=laz[p]*(m-l+);
iv[a]+=laz[p]*(m+l)*(m-l+)/;
}
if(b){
laz[b]+=laz[p];
v[b]+=laz[p]*(r-m);
iv[b]+=laz[p]*(r+m+)*(r-m)/;
}
laz[p]=;
} inline void update(int p){
v[p]=v[ch[p][]]+v[ch[p][]];
iv[p]=iv[ch[p][]]+iv[ch[p][]];
} void build(int &p,int l,int r){
if(!p) p=++pct;
if(l<r){
int m=l+r>>;
build(ch[p][],l,m);
build(ch[p][],m+,r);
}
} inline void add(int p,int l,int r,int x){
laz[p]+=x;
v[p]+=1ll*(r-l+)*x;
iv[p]+=1ll*(r+l)*(r-l+)/*x;
pushdown(p,l,r);
} void ins(int p,int l,int r,int x,int y,int z){
if(x<=l&&r<=y){
add(p,l,r,z);
}else{
pushdown(p,l,r);
int m=l+r>>;
if(x<=m) ins(ch[p][],l,m,x,y,z);
if(y>=m+) ins(ch[p][],m+,r,x,y,z);
update(p);
}
} ll query(int p,int l,int r,int x){
pushdown(p,l,r);
if(r<=x){
return v[p]*(x+)-iv[p];
}else{
int m=l+r>>;ll re;
re=query(ch[p][],l,m,x);
if(x>=m+) re+=query(ch[p][],m+,r,x);
return re;
}
} ll query2(int p,int l,int r,int x){
if(r<=x){
return v[p];
}else{
pushdown(p,l,r);
int m=l+r>>;ll re;
re=query2(ch[p][],l,m,x);
if(x>=m+) re+=query2(ch[p][],m+,r,x);
return re;
}
} int main(){
// freopen("6253.in","r",stdin);
rei i,j,k;
N=rd();rd();
for(i=;i<=N;i++) tmp[i]=num[i]=rd();
sort(tmp+,tmp+N+);M=unique(tmp+,tmp+N+)-tmp-;
for(i=;i<=N;i++) num[i]=lower_bound(tmp+,tmp+M+,num[i])-tmp;
for(i=N;i;i--){
nxt[i]=hd[num[i]];hd[num[i]]=i;
}
L=N+;
build(root,-L,L);
ins(root,-L,L,,,);
for(i=;i<=M;i++){
int sum=;
for(j=hd[i],k=;j;j=nxt[j]){
if(k<j){
ans+=query(root,-L,L,sum-)-query(root,-L,L,sum-j+k-);
ins(root,-L,L,sum-j+k,sum-,);
sum-=j-k;
}sum++;
ans+=query2(root,-L,L,sum-);
ins(root,-L,L,sum,sum,);
k=j+;
}
ans+=query(root,-L,L,sum-)-query(root,-L,L,sum-N+k-);
sum=;
for(j=hd[i],k=;j;j=nxt[j]){
if(k<j){
ins(root,-L,L,sum-j+k,sum-,-);
sum-=j-k;
}sum++;
ins(root,-L,L,sum,sum,-);
k=j+;
}
}
printf("%lld\n",ans);
return ;
}
loj6253/luogu4062-Yazid的新生舞会的更多相关文章
- 【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] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- [loj 6253] Yazid的新生舞会
(很久之前刷的题现在看起来十分陌生a) 题意: 给你一个长度为n的序列A,定义一个区间$[l,r]$是“新生舞会的”当且仅当该区间的众数次数严格大于$\frac{r-l+1}{2}$,求有多少子区间是 ...
- 【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 ...
- bzoj 5110 Yazid的新生舞会
题目大意: 一个数列,求有多少个区间$[l,r]$满足该区间的众数出现次数大于$\lceil \frac{r-l}{2} \rceil$ 思路: 对于一个区间满足条件的众数明显是唯一的 所以设该数的前 ...
随机推荐
- STM32通用定时器原理
/************************************************************************************************ 转载 ...
- 初识TPOT:一个基于Python的自动化机器学习开发工具
1. TPOT介绍 一般来讲,创建一个机器学习模型需要经历以下几步: 数据预处理 特征工程 模型选择 超参数调整 模型保存 本文介绍一个基于遗传算法的快速模型选择及调参的方法,TPOT:一种基于Pyt ...
- R实战 第九篇:数据标准化
数据标准化处理是数据分析的一项基础工作,不同评价指标往往具有不同的量纲,数据之间的差别可能很大,不进行处理会影响到数据分析的结果.为了消除指标之间的量纲和取值范围差异对数据分析结果的影响,需要对数据进 ...
- R实战 第六篇:数据变换(aggregate+dplyr)
数据分析的工作,80%的时间耗费在处理数据上,而数据处理的主要过程可以分为:分离-操作-结合(Split-Apply-Combine),也就是说,首先,把数据根据特定的字段分组,每个分组都是独立的:然 ...
- SQL SERVER 2008R2 安装问题
背景 今天帮可以安装数据库.操作系统是windows server 2012 标准版, 安装SQL SERVER 2008R2 . 运行安装程序,提示如下 这是因为两者之间存在兼容性问题. ...
- Microsoft Dynamics CRM 增删改子表汇总子表的某个字段到主表的某个字段(通用插件)
背景 经常有某个汇总子表的数量到主表的总数量,或者汇总子表的总价到主表的总价这种需求. 传统的做法: 1.就是为每个子表实体单独写成一个插件,但是这样不好复用. 2.主表的汇总字段是汇总货币类型,但是 ...
- 最简单的iOS网络请求
做iOS开发,说到网络请求,大家可能都不约而同的提到AFN,可以说大家的网络请求都是用AFN封装而成,AFN的强大易用的确很好. 但是版本升级就会出现一些问题,所以就自己基于iOS原生封装了一个网络请 ...
- css怎样去掉多个Img标签之间的间隙
在写css的时候经常会遇到这样的情况,两张宽度加起来是2n的图片,在宽度为2n的容器中放不下,这是因为两张图片之间有一段间隙的缘故,产生这种现象的原因是浏览器把两个img标签之间的空格当成了空白节点. ...
- shell脚本之基础
配置启动界面 vim /etc/inittab/ init3配置网卡 重启生效system-config-network网卡配置文件vim /etc/sysconfig/network-script ...
- Python3 str去除空格
一.去除str两端空格(strip()) a.去除左端空格 lstrip() str0='abcdef' str1=' abcdef' print(str0) print(str1.lstrip() ...