Luogu 4755 Beautiful Pair
分治 + 主席树。
设$solve(l, r)$表示当前处理到$[l, r]$区间的情况,我们可以找到$[l, r]$中最大的一个数的位置$mid$,然后扫一半区间计算一下这个区间的答案。
注意,这时候左半边是$[l, mid]$,而右区间是$[mid, r]$,我们在这个区间处理的时候要算完所有$mid$的情况,然后我们每一次分治的时候去处理$solve(l, mid - 1)$和$solve(mid + 1, r)$,要不然当$mid$是端点的时候就会无限递归下去。
问题转化快速算出一个区间内$\leq$一个数的数,只要一棵主席树就可以解决了,区间最大值可以用$ST$表维护出来。
我们每一次选取一个比较短的区间去枚举然后算另一个区间的答案,这样子每一次计算区间的长度至少减少一半,这样子可以保证时间复杂度。
时间复杂度$O(nlog^2n)$。
Code:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = 1e5 + ;
const int Lg = ;
const ll inf = 1LL << ; int n, tot = ;
ll ans = 0LL, a[N], num[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void chkMax(T &x, T y) {
if(y > x) x = y;
} namespace ST {
int st[N][Lg], len[N]; inline int bet(int x, int y) {
return a[x] > a[y] ? x : y;
} inline void prework() {
for(int j = ; j <= ; j++)
for(int i = ; i + ( << j) - <= n; i++)
st[i][j] = bet(st[i][j - ], st[i + ( << (j - ))][j - ]);
} inline int qMax(int x, int y) {
int k = len[y - x + ];
return bet(st[x][k], st[y - ( << k) + ][k]);
} } using namespace ST; namespace SegT {
struct Node {
int lc, rc;
ll sum;
} s[N * ]; int root[N], nodeCnt = ; #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define mid ((l + r) >> 1) void ins(int &p, int l, int r, int x, int pre) {
s[p = ++nodeCnt] = s[pre];
++sum(p);
if(l == r) return; if(x <= mid) ins(lc(p), l, mid, x, lc(pre));
else ins(rc(p), mid + , r, x, rc(pre));
} ll query(int r1, int r2, int l, int r, int x, int y) {
if(x > y) return 0LL;
if(x <= l && y >= r) return sum(r2) - sum(r1); ll res = 0LL;
if(x <= mid) res += query(lc(r1), lc(r2), l, mid, x, y);
if(y > mid) res += query(rc(r1), rc(r2), mid + , r, x, y);
return res;
} #undef mid } using namespace SegT; void solve(int l, int r) {
if(l > r) return; int mid = qMax(l, r);
if(mid - l < r - mid) {
for(int i = l; i <= mid; i++) {
int pos = upper_bound(num + , num + + tot, (ll) (num[a[mid]] / num[a[i]])) - num - ;
ans += query(root[mid - ], root[r], , tot, , pos);
}
} else {
for(int i = mid; i <= r; i++) {
int pos = upper_bound(num + , num + + tot, (ll) (num[a[mid]] / num[a[i]])) - num - ;
ans += query(root[l - ], root[mid], , tot, , pos);
}
} solve(l, mid - ), solve(mid + , r);
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(a[i]);
len[i] = log2(i), st[i][] = i;
num[++tot] = a[i];
}
prework(); num[++tot] = inf;
sort(num + , num + + tot);
tot = unique(num + , num + tot + ) - num - ; for(int i = ; i <= n; i++) {
a[i] = lower_bound(num + , num + + tot, a[i]) - num;
ins(root[i], , tot, a[i], root[i - ]);
} /* for(int i = 1; i <= n; i++)
printf("%lld ", a[i]);
printf("\n"); */ solve(, n); printf("%lld\n", ans);
return ;
}
Luogu 4755 Beautiful Pair的更多相关文章
- luogu P4755 Beautiful Pair
luogu 这题有坨区间最大值,考虑最值分治.分治时每次取出最大值,然后考虑统计跨过这个位置的区间答案,然后两边递归处理.如果之枚举左端点,因为最大值确定,右端点权值要满足\(a_r\le \frac ...
- 洛谷4755 Beautiful Pair (分治)
题目描述 小D有个数列 \(a\),当一个数对 \((i,j)(i\le j)\) 满足\(a_i\)和\(a_j\)的积 不大于 \(a_i \cdots a_j\) 中的最大值时,小D认为这个数对 ...
- 「LGR-049」洛谷7月月赛 D.Beautiful Pair
「LGR-049」洛谷7月月赛 D.Beautiful Pair 题目大意 : 给出长度为 \(n\) 的序列,求满足 \(i \leq j\) 且 $a_i \times a_j \leq \max ...
- [luogu4755]Beautiful Pair
[luogu4755]Beautiful Pair luogu 第一次写最大值分治感觉有点丑 每次找到最大值mid,扫小的一边,主席树查大的一边小于等于\(\frac{a[mid]}{a[i]}\)的 ...
- 【题解】P4755 Beautiful Pair(启发式合并的思路+分治=启发式分治)
[题解]P4755 Beautiful Pair upd: 之前一个first second烦了,现在AC了 由于之前是直接抄std写的,所以没有什么心得体会,今天自己写写发现 不知道为啥\(90\) ...
- Luogu4755 Beautiful Pair 最值分治、主席树
传送门 整天做一些模板题感觉药丸 设\(val_i\)表示第\(i\)个位置的值 看到区间最大值考虑最值分治.对于当前的区间\([l,r]\),找到区间最大值\(mid\),递归\([l,mid-1] ...
- luoguP4755 Beautiful Pair
https://www.luogu.org/problemnew/show/P4755 考虑分治,在 [l, r] 区间中用线段树找到最大的一个点,处理经过它的可行数对的个数,统计个数可以离线树状数组 ...
- 洛谷$P4755\ Beautiful\ Pair$ 最大值分治
正解:最大值分治 解题报告: 传送门$QwQ$ 昂考虑如果已经钦定了点$x$是这个$max$了,然后现在要求有多少对$[l,r]$满足$a_x=max\left\{a_i\right\},i\in[l ...
- 洛谷 P4755 - Beautiful Pair(主席树+分治+启发式优化)
题面传送门 wssb,我紫菜 看到这类与最大值统计有关的问题可以很自然地想到分治,考虑对 \([l,r]\) 进行分治,求出对于所有 \(l\le x\le y\le r\) 的点对 \((x,y)\ ...
随机推荐
- HTML中id与name的用法
可以说几乎每个做过Web开发的人都问过,到底元素的ID和Name有什么区别阿?为什么有了ID还要有Name呢? 而同样我们也可以得到最经典的答案:ID就像是一个人的身份证号码,而Name就像是他的名字 ...
- 关于modelsim添加库的说明
声明:以下纯属个人习惯. 1.工程建好后添加一个编译好的库的方法是:file->new->library选择a map to an existing library.然后将这个库在你这工程 ...
- JAMstack 技术要点
1. 简要说明 Modern web development architecture based on client-side JavaScript, reusable APIs,and preb ...
- Redis 字符串(String)
Redis 字符串(String) Redis 字符串数据类型的相关命令用于管理 redis 字符串值,基本语法如下: 语法 redis 127.0.0.1:6379> COMMAND KEY_ ...
- ORACLE 11G负载均衡测试
Oracle 11g R2中,引入了SCAN(Single Client Access Name)的特性.该特性的好处在于,在数据库与客户端之间,添加了一层虚拟的服务层,就是所谓的SCAN IP以及S ...
- CentOS6安装vsftpd
练习:完成vsftpd配置 (1) 禁锢系统用户于家目录 [root@node3 ~]# yum -y install vsftpd [root@node3 ~]# vim /etc/vsftpd/v ...
- 转 : 配置 mysql-advanced-5.6.21-winx64 免安装版
mySQL包:mysql-advanced-5.6.21-winx64.zip 下载地址:https://edelivery.oracle.com/EPD/Search/handle_go 服务器版本 ...
- erlang的dict和maps模块
erlang在r17以后增加了map这个数据结构,在之前,类似map的需求用dict模块来实现,这里直接贴一下相关的操作 dict D = dict:new(). D1 = dict:store(k1 ...
- MATLAB01
在命令行窗口输入edit就会进入代码编写区,编写完毕点击运行后会先进行保存,然后再执行代码,保存时候一定要以英文开头. 数组 创建矩阵: 函数名 描述 zero(m,n) 创建m行n列全零矩阵 one ...
- linux字符界面下root用户无法登录成功
os: rhel5.6_x86_64 ———————————————————————————————————————————— 故障:图形界面登录正常,其他一切正常,但是切换到字符界面时,输入用户ro ...