欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

洛谷p4755 Beautiful Pair

程序员文章站 2022-05-08 17:42:35
...

神仙分治题,
我们假设当前分到了\([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));   
}