题目描述

小D有个数列 \(a\),当一个数对 \((i,j)(i\le j)\) 满足\(a_i\)和\(a_j\)的积 不大于 \(a_i \cdots a_j\) 中的最大值时,小D认为这个数对是美丽的.请你求出美丽的数对的数量。

输入格式
第一行输入一个整数 \(n\),表示元素个数。 第二行输入 \(n\) 个整数 \(a_1,a_2,a_3,\cdots,a\),为所给的数列。

输出格式:
输出一个整数,为美丽的数字对数。

其中\(m\le 10^5,a_i \le 10^9\)

这个题,看到题的第一想法就是QwQ,一看就是dp或者一些恶心的数据结构题,但是想了一会dp,发现不太可行。那么我们可以考虑通过分治 来解决这个问题

我们考虑,对于一个区间\([l,r]\),我们可以通过这个区间的\(mx\)(表示最大的\(a_i\))来解决,因为要求乘积不能大于区间的最大值,所以我们在 计算区间的时候,\(mx\)一般情况下是不能和别的数进行组合的。所以说,按照mx来分组,那么当前区间的答案就是\([l,mx-1]\)的答案加上\([mx+1,r]\),然后加上两个区间产生的贡献。
QwQ那么怎么求左右区间产生的贡献呢

我们考虑,对于一个固定的左端点\(l\),我们需要在\([mx+1,r]\)区间找出,小于\(\lfloor \frac{mx}{a_l} \rfloor\)的数的个数
然后我们枚举所有的左端点,然后数一数,最后考虑\(mx\)这个端点可以不可以跟左边的这个区间进行组合

那么我们应该怎么求一个区间内小于等于一个数的个数呢

QwQ
呀,BIT!树状数组 嗯!
我们考虑将每个数进行离散化,然后维护一个权值树状数组,然后我们每次只需要\(query(find(\lfloor \frac{mx}{a_l} \rfloor))\)就可以,其中\(find\)的函数的作用是,找到这个值离散化后的小于等于它的最大的值,其实可以直接\(lower_bound\)

记得离散化!

还有一些人会问,这个算法的时间复杂度可以保证吗?QwQ具体的证明我也不是很会呀,不过可以感性l理解

如果我们每次挑选的\(mx\),都选择比较中间的,那么我们可以大致理解是\(O(nlogn)\)的

直接上代码

dfs版的分治

非常理解,个人敢接

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<unordered_map>
using namespace std;inline int read()
{int x=0,f=1;char ch=getchar();while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;
}const int maxn =  1e5+1e2;int c[maxn];
int a[maxn];
int b[maxn];
int n,m;
int dp[maxn][23];
int p[maxn];
int tmp = 0;
unordered_map<int,int> mp;struct Node{int id,val;
};Node g[maxn];int lowbit(int x)
{return (-x) & x;
}void update(int x,int p)
{for (int i=x;i<=n;i+=lowbit(i)) c[i]+=p;
}long long query(int x)
{long long ans=0;for (int i=x;i;i-=lowbit(i)) ans+=(long long)c[i];return ans;
}int find(int x)
{if (x>p[n]) return tmp;return g[upper_bound(p+1,p+1+n,x)-p-1].id;
}bool cmp(Node a,Node b)
{return a.val<b.val;
}int countmax(int x,int y)
{int k = log2(y-x+1);return max(dp[x][k],dp[y-(1 <<k)+1][k]);
}void init()
{for (int j=1;j<=21;j++)for (int i=1;i<=n;i++){if (i+(1 << j)-1<=n){dp[i][j]=max(dp[i][j-1],dp[i+(1 << (j-1))][j-1]);}}
}long long solve(int l,int r)
{if (l>r) return 0;if (l==r)  {if (a[l]==1)return 1;else return 0;}long long cnt=0;int mid = (l+r) >> 1;int mx = countmax(l,r),pos=0;for (int i=l;i<=r;i++){if (a[i]==mx) {if (!pos || abs(mid-i)<abs(mid-pos)) pos=i;}}cnt+=solve(l,pos-1);cnt+=solve(pos+1,r);for (int i=pos+1;i<=r;i++) update(b[i],1);for (int i=l;i<=pos;i++) cnt=cnt+(query(find(mx/a[i])));for (int i=pos+1;i<=r;i++) update(b[i],-1);//cout<<l<<" "<<r<<" "<<cnt<<endl;for (int i=l;i<=pos-1;i++) update(b[i],1);cnt=cnt+(query(find(mx/a[pos])));for (int i=l;i<=pos-1;i++) update(b[i],-1); //out<<l<<" "<<r<<" "<<cnt<<endl;if (a[pos]==1) cnt++;return cnt;
}int main()
{n=read();for (int i=1;i<=n;i++) a[i]=read(),g[i].id=i,g[i].val=a[i],dp[i][0]=a[i];init();sort(g+1,g+1+n,cmp);for (int i=1;i<=n;i++){if (g[i].val!=g[i-1].val) tmp++;b[g[i].id]=tmp;mp[a[g[i].id]]=tmp;}//for (int i=1;i<=n;i++) cout<<b[i]<<" "; memset(g,0,sizeof(g));for (int i=1;i<=n;i++) p[i]=a[i],g[i].val=a[i],g[i].id=b[i];sort(g+1,g+1+n,cmp);sort(p+1,p+1+n);//cout<<endl;long long ans=solve(1,n);cout<<ans;return 0;
}

转载于:https://www.cnblogs.com/yimmortal/p/10160923.html

洛谷4755 Beautiful Pair (分治)相关推荐

  1. 洛谷 - P4755 Beautiful Pair(笛卡尔树+主席树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a,现在一个数对 ( i , j ) 如果满足 a[ i ] * a[ j ] <=max( a[ i ] ~ a[ j ] ),则称其 ...

  2. 洛谷T44252 线索_分治线段树_思维题

    分治线段树,其实就是将标记永久化,到最后再统一下传所有标记. 至于先后顺序,可以给每个节点开一个时间戳. 一般地,分治线段树用于离线,只查询一次答案的题目. 本题中,标记要被下传 222 次. Cod ...

  3. Luogu 4755 Beautiful Pair

    分治 + 主席树. 设$solve(l, r)$表示当前处理到$[l, r]$区间的情况,我们可以找到$[l, r]$中最大的一个数的位置$mid$,然后扫一半区间计算一下这个区间的答案. 注意,这时 ...

  4. 洛谷 4178 Tree——点分治

    题目:https://www.luogu.org/problemnew/show/P4178 点分治.如果把每次的 dis 和 K-dis 都离散化,用树状数组找,是O(n*logn*logn),会T ...

  5. 洛谷 P1498 南蛮图腾 分治递归过程详解

    题目描述 自从到了南蛮之地,孔明不仅把孟获收拾的服服帖帖,而且还发现了不少少数民族的智慧,他发现少数民族的图腾往往有着一种分形的效果,在得到了酋长的传授后,孔明掌握了不少绘图技术,但唯独不会画他们的图 ...

  6. 洛谷 P2400 秘密文件【分治】

    ... 题目: 题意: 分析: 代码: 题目: 传送门 题意: 给出一个较长的字符串,要求我们按照规则进行化简,使得其长度最短 分析: 直接使用分治的思想,对于区间l−rl-rl−r,我们枚举一个分界 ...

  7. [WC2005]双面棋盘,洛谷P4121,线段树分治+可撤销并查集

    正题 这题主要是来练手的,因为没写过可撤销的并查集,大概就是把每一个格子看成一个点,然后格子直接的边有很多的出现区间,把这些出现区间和对应的颜色打到线段树上,然后用可撤销的并查集来维护就可以了. #i ...

  8. 洛谷 4115 Qtree4——链分治

    题目:https://www.luogu.org/problemnew/show/P4115 论文:https://wenku.baidu.com/view/1bc2e4ea172ded630b1cb ...

  9. 【洛谷习题】南蛮图腾

    题目链接:https://www.luogu.org/problemnew/show/P1498 不好实现... 这道题在洛谷的分类是分治,我用的方法就是分治,不过却刷新的我对分治的认识.以前见过的分 ...

  10. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

最新文章

  1. 语音信号处理_书单 | 语音研究进阶指南
  2. 判断数组对象里面的某个属性全部为true才执行下一步操作
  3. 计算力学专业和计算机专业区别,力学类包括哪些专业
  4. 十四、PHP框架Laravel学习笔记——构造器的排序分组、子查询
  5. yii mysql 查询 类型转换_Yii2.0 API改造(返回数据库对应字段数据类型)
  6. 战争学院服务器不稳定,英雄联盟服务器突然崩溃坑玩家!战争学院玩家全被强制下线...
  7. day26-2 基于TCP协议的套接字编程
  8. Kyoto Tycoon挂载LevelDB,编译安装篇
  9. 【安全问道】系列:阿里带你3分钟掌握一个互联网
  10. 自定义jQuery翻页插件
  11. 矩阵乘法公式c语言,c语言矩阵相乘
  12. 文本文档怎么转换为html文件,win10系统下如何将文本文档转换为网页
  13. 如何绘制高质量业务流程图
  14. Matlab 均值滤波与中值滤波
  15. faster rcnn:towards real-time object detection with region proposal network
  16. aardio - 伪装进程测试
  17. 学会这几点,不懂代码也能做出炫酷可视化大屏!
  18. 《MLB棒球创造营》:走近棒球运动·亚利桑那响尾蛇队
  19. POI读取word里面的表格并处理数据
  20. 如何获得coredump

热门文章

  1. 功能自动化接入持续集成方案
  2. javascript:typeof与instanceof区别
  3. minicap和minitouch安装
  4. 详解文本分类之多通道CNN的理论与实践
  5. 【珍藏版】长文详解python正则表达式
  6. 【前沿】详细讲解Transformer新型神经网络在机器翻译中的应用
  7. 20200308——多项式回归预测工资
  8. 机翻测评 | 友商翻译 VS 火山翻译-中译英语向
  9. 机器学习基础算法29-EM实践
  10. 机器学习基础算法13-回归实例-时间序列分析ARIMA