神仙分治题,
我们假设当前分到了\([l,r]\)。
那么我们就可以做一个假设:设\(p\)为这个区间内最大的值\(mx\),其编号为\(p\)。
那么这里有一部分的答案就是\([l,p - 1] + [p + 1,r]\)
为什么?其实这个想一想就知道。
因为我们一般是不会用这个数跟其他的数结合的。
那么我们就结束了左边和右边单独计算的情况。
那么还有就是左边和右边混起来的情况。
这个其实也很好解决。
我们已经知道了当前的最大值,只需要枚举左边然后算一下有多少个数小于\(\frac{mx}{a_l}\)(\(l\)为当前枚举到的左边界)。
这里可以离散化然后用树状数组完成(具体操作省去)。
同样的,算一下\([l,p - 1]\)时的情况,因为上面一轮算过了\([p + 1,r]\),所以这里只要计算一下边界为\(p\)就行了。
具体复杂度应该接近于\(O(n log n)\)
不过极限情况下是能够到达\(O(n ^ 2)\) ,
不过我觉得应该没有人会卡你,
能过就够了。
#include <bits/stdc++.h>
const int maxn = 1e5 + 10;
typedef long long ll;
template<class t> inline void read(t& res) {
res = 0; bool neg = 0; char ch = getchar();
while(!isdigit(ch))
neg |= ch == '-', ch = getchar();
while(isdigit(ch))
res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
if(neg)
res = -res;
}
template<class t1,class t2> inline void cmax(t1& a,t2 b) {
if(a < b)
a = b;
}
template<class t> inline t _abs(t x) {
return x < 0 ? -x : x;
}
int n, m, i, j, k;
int a[maxn], num[maxn], MX, d[maxn];
struct node {
int id, va;
node() { id = va = 0; }
node(int _id,int _va) {
id = _id; va = _va;
}
inline friend bool operator < (node a,node b) {
return a.va < b.va;
}
} f[maxn];
inline void lsh() {
std::sort(f + 1,f + n + 1);
int cnt = 0;
for(int i = 1;i <= n;i++) {
if(f[i].va != f[i - 1].va)
cnt++;
num[ f[i].id ] = cnt;
}
for(int i = 1;i <= n;i++)
f[i] = node(num[i],a[i]);
std::sort(f + 1,f + n + 1);
std::sort(d + 1,d + n + 1);
}
struct binary_index_tree {
int c[maxn];
inline void add(int x,int y) {
while(x <= n)
c[x] += y, x += x & -x;
}
inline int ask(int x) {
int res = 0;
while(x)
res += c[x], x -= x & -x;
return res;
}
} A;
inline int get(int x) {
if(x > d[n])
return 0;
else
return f[std::upper_bound(d + 1,d + n + 1,x) - d - 1].id;
}
ll calc(ll l,ll r) {
if(l > r)
return 0;
if(l == r)
return a[l] == 1;
ll res = 0, mid = (l + r) >> 1, mx = -1, pos;
for(int i = l;i <= r;i++) {
if(a[i] > mx) {
mx = a[i];
pos = i;
} else if(a[i] == mx && (_abs(i - mid) < _abs(pos - mid))) {
pos = i;
}
}
res += calc(l,pos - 1);
res += calc(pos + 1,r);
for(int i = pos + 1;i <= r;i++)
A.add(num[i],1);
for(int i = l;i <= pos;i++)
res += A.ask(get(mx / a[i]));
for(int i = pos + 1;i <= r;i++)
A.add(num[i],-1);
for(int i = l;i <= pos - 1;i++)
A.add(num[i],1);
res += A.ask(get(mx / a[pos]));
for(int i = l;i <= pos - 1;i++)
A.add(num[i],-1);
if(a[pos] == 1)
res++;
return res;
}
int main() {
read(n);
for(int i = 1;i <= n;i++)
read(a[i]), f[i] = node(i,a[i]), d[i] = a[i];
lsh();
printf("%lld\n",calc(1,n));
}