题目大意:
  给你一个长度为$n(n\leq 5\times 10^5)$的序列$A_{1\sim n}$。求满足区间众数在区间内出现次数严格大于$\lfloor\frac{r-l+1}{2}\rfloor$的区间$[l,r]$的个数。

思路:
  分治。
  对于一个区间$[l,r]$,设$mid=\lfloor\frac{l+r}{2}\rfloor$,我们可以求出所有经过$mid$的区间内能够成为众数的所有数。
  不难发现所有的区间众数满足如下一个性质:如果$x$是区间$[l,r]$的众数,那么对于$l\leq x\leq r$,$x$一定是区间$[l,k]$或区间$(k,r]$的众数。
  利用这一性质,我们可以令$k=mid$,这样就可以$O(n)$从$mid$出发往左右两边扫,求出能够成为众数的所有数。
  接下来枚举每个众数$x$,求一下当前$[l,r]$区间中,以$x$作为众数的子区间个数。
  具体我们可以先从$mid$往左扫,设往左扫到的端点为$b$,记录一下对于不同的$b$,$mid-b+1-cnt[x]$不同取值的出现次数。然后再往右扫,求出对于当前右端点$e$,求出满足$e-b+1-cnt[x]>\lfloor\frac{e-b+1}{2}\rfloor$的区间$[b,e]$的个数,这可以用前缀和快速求出。
  这样我们就统计了区间$[l,r]$,经过$mid$的所有子区间。
  对于不经过$mid$的子区间可以递归求解。
  递归树中,每一层区间长度加起来是$n$,可能的众数个数有$\log n$个,每一层的时间复杂度是$O(n\log n)$。总共有$\log n$层,总的时间复杂度是$O(n\log^2 n)$。

 #include<cstdio>
#include<cctype>
#include<algorithm>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=;
int a[N],pos[N],num[N],cnt[N*];
int64 ans;
void solve(const int &l,const int &r) {
if(l==r) {
ans++;
return;
}
const int mid=(l+r)/;
solve(l,mid);
solve(mid+,r);
for(register int i=mid;i>=l;i--) {
if(++cnt[a[i]]>(mid-i+)/) {
if(!pos[a[i]]) {
num[pos[a[i]]=++num[]]=a[i];
}
}
}
for(register int i=mid+;i<=r;i++) {
if(++cnt[a[i]]>(i-mid)/) {
if(!pos[a[i]]) {
num[pos[a[i]]=++num[]]=a[i];
}
}
}
for(register int i=l;i<=r;i++) {
pos[a[i]]=cnt[a[i]]=;
}
for(register int i=;i<=num[];i++) {
int sum=r-l+,max=sum,min=sum;
cnt[sum]=;
for(register int j=l;j<mid;j++) {
if(a[j]==num[i]) {
sum++;
} else {
sum--;
}
max=std::max(max,sum);
min=std::min(min,sum);
cnt[sum]++;
}
if(a[mid]==num[i]) {
sum++;
} else {
sum--;
}
for(register int i=min;i<=max;i++) {
cnt[i]+=cnt[i-];
}
for(register int j=mid+;j<=r;j++) {
if(a[j]==num[i]) {
sum++;
} else {
sum--;
}
ans+=cnt[std::min(max,sum-)];
}
for(register int i=min;i<=max;i++) {
cnt[i]=;
}
}
num[]=;
}
int main() {
const int n=getint(); getint();
for(register int i=;i<=n;i++) {
a[i]=getint();
}
solve(,n);
printf("%lld\n",ans);
return ;
}

[BZOJ5110]Yazid的新生舞会的更多相关文章

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

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

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

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

  3. 【bzoj5110】Yazid的新生舞会

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

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

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

  5. 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会

    题解: 没笔的时候我想了一下 发现如果不是出现一半次数而是k次,并不太会做 然后我用前缀和写了一下发现就是维护一个不等式: 于是就可以随便维护了

  6. 【bzoj5110】[CodePlus2017]Yazid 的新生舞会 Treap

    题目描述 求一个序列所有的子区间,满足区间众数的出现次数大于区间长度的一半. 输入 第一行2个用空格隔开的非负整数n,type,表示序列的长度和数据类型.数据类型的作用将在子任务中说明. 第二行n个用 ...

  7. BZOJ5110 CodePlus2017Yazid 的新生舞会(线段树)

    考虑统计每个数字的贡献.设f[i]为前缀i中该数的出现次数,则要统计f[r]-f[l]>(r-l)/2的数对个数,也即2f[r]-r>2f[l]-l. 注意到所有数的f的总变化次数是线性的 ...

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

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

  9. 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

    学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...

随机推荐

  1. php天龙八部

    <?php /* 一.操作步骤: 连接MySQL数据库 判断是否连接成功 选择数据库 设置字符集 准备SQL语句 向MySQL服务发送SQL语句 解析处理结果集 释放结果集,关闭数据库连接 */ ...

  2. shell之route命令相关

    使用下面的 route 命令可以查看 Linux 内核路由表. # route Destination Gateway Genmask Flags Metric Ref Use Iface 192.1 ...

  3. LeetCode(一)

    Q&A ONE Given an array of integers, return indices of the two numbers such that they add up to a ...

  4. 深入解析Vuex实战总结

    这篇文章主要介绍了Vuex的初探与实战小结,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. 1.背景 最近在做一个单页面的管理后台项目,为了提高开 ...

  5. 关于Yarn源码那些事-前传之ResourceManager篇(一)初始化

    在关于Yarn那些事的博客里,介绍的主要是针对任务提交的一个动态流程说明,而其中牵涉到的一些细节问题,必须通过Resourcemanager的启动和NodeManager的启动,来更好的说明. 而本系 ...

  6. 如何设置两个AD域控制器

    目的:这要为了测试,哈哈哈哈. 其实是为了AD域控的高可用性.一个域控down了,另一个可以顶上去. 如何设置:参考http://lgzeng2360.blog.51cto.com/275998/10 ...

  7. HDU2041 简单DP+规律

    超级楼梯 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. MFC 按钮

    ((CButton *)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);//选上 ((CButton *)GetDlgItem(IDC_RADIO1))-> ...

  9. mac使用基础

    Mac 系统的桌面 Mac 的桌面是一个很炫的3D, 背景是一张“星空”图. 2 Dock:  在桌面的下方有一排图标, 叫Dock, 用来快速启动程序, 进入文件夹, 它同时还可以停靠正在运行的程序 ...

  10. 接下来打算写一下visual stuido 2013使用git进行远端管理。

    虽然我有了vs的账号,也vs2013开始已经可以进行远端的账户管理了,可是vs的版控毕竟有些依赖vs,想想还是用git吧 今天把这个环境的整套都弄地基本熟了.记录一下,算是一个小结.开始搭建系统框架