洛谷p4755 Beautiful Pair

神仙分治题,
我们假设当前分到了\([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));   
}
posted @ 2019-07-15 17:31  _connect  阅读(195)  评论(0编辑  收藏  举报
Live2D