[HackerRank] Array Pairs[101 Hack 42]

Problem

Consider an array of $$n$$ integers, $$A = [a1, a_2, \ldots, a{n}]$$. Find and print the total number of $$(i,j) $$ pairs such that $$ai \times a_j \le max(a_i, a{i+1}, \ldots, a_j) $$ where $$i \lt j$$.

Input Format

The first line contains an integer,$$ n $$, denoting the number of elements in the array.
The second line consists of $$ n $$space-separated integers describing the respective values of$$ a_1 , a_2,a_3, \cdots a_n$$.

Constraints

$$ 1 \leq n \leq 5 \times 10^5 $$

$$ 1 \leq a_i \leq 10^9 $$

Scoring

$$ 1 \leq n \leq 1000 $$ for 25% of the test cases.

$$ 1 \leq n \leq 10^5 $$ for 50% of the test cases.

$$ 1 \leq n \leq 5 \times 10^5 $$ for 100% of the test cases.

Output Format

Print a long integer denoting the total number $$(i,j)$$ pairs satisfying $$ ai \times a_j \leq max(a_i,a{i+1},a{i+2}, \cdots ,a_j )$$where $$(i<j)$$

Sample Input

5
1 1 2 4 2

Sample Output

8

Explanation

There are eight pairs satisfying the given criteria:(1,2),(1,3),(1,4),(1,5),(2,3),(2,4),(2,5) and (3,5). Thus, we printas 8 our answer.

思路

笛卡尔树

方案1: 参考: http://blog.csdn.net/samjia2000/article/details/52997874

假如我们已经知道了$$max(ai,a{i+1},...,aj)$$是$$v$$,那么对于一个i我们就可以知道$$a_j$$的取值范围应该为$$[1,\frac{a_i}{v}]$$于是我们可以建出笛卡尔树,对于笛卡尔树上的一个点,我们有两种方法来求出$$max(a_i,a{i+1},...,a_j)$$是$$v$$的合法的$$(i,j)$$的个数,一是枚举$$i$$,利用数据结构统计$$j$$的个数,二是枚举$$j$$,统计i的个数,显然如果我们非要从这两种里面选一种的话,我们会选择枚举次数少的。

那么这样做为什么不会使得询问的次数特别多呢?显然,一个最坏的情况下,我们建出的笛卡尔树应该是颗满二叉树,而当前情况下共有$$log_2n$$层,每层$$n$$个,由于要用到数据结构,所以这样做是$$O(nlog_2 ^2n)$$的。

这题的难点主要在于要想到用笛卡尔树,还要想到挑选个数小的那边进行枚举。

方案2:

为了方便求出区间最大值,我们先建出笛卡尔树。

考虑枚举笛卡尔树上每一个点,显然可以得到它作为最大值的区间。

如果我们枚举这个区间的左半部分的一个数,结合当前最大值,我们就知道右半区间的合法的数的取值范围。也就是我们只需要查询右半区间有多少个数小于等于某数即可。

但是这样显然是$$O(n^2)$$的,但是不虚,使用类似启发式合并的想法,如果右边比左边长度小,我们就枚举右边!这样每次枚举长度不会超过整个区间的一半!也就是说枚举的复杂度是$$O(nlog_2n)$$的!

至于查询,你可以选择打一个主席树在线查。当然也可以先把所有区间询问变为两个前缀询问相减,然后先存下来,遍历完笛卡尔树之后再统一使用树状数组计算。

时间复杂度$$O(nlog_2 ^2n)$$。

注意特判当前最大值和别的数组合造成的贡献。

代码

方案1:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

const int N = 5e5+10;

typedef long long LL;

int tree[N];
struct sj{
    int ty,l,r,x;
    friend bool operator <(sj a,sj b){
        if (a.x!=b.x)return a.x<b.x;
        return a.ty<b.ty;
    }
}q[N*20];
int sta[N],k,m;
int n;
LL ans;
int L[N],R[N],a[N],fa[N],rt,s[N],f[N];

void add(int ty,int l,int r,int x){
    q[++m].ty=ty;q[m].l=l;q[m].r=r;q[m].x=x;
}

void bfs(){
    int he=0,ta=1;
    f[1]=rt;
    while(he<ta){
        int x=f[++he];
        if (L[x])f[++ta]=L[x];
        if (R[x])f[++ta]=R[x];
    }
    fd(d,n,1){
        int x=f[d];
        s[x]=s[L[x]]+s[R[x]]+1;
        if(L[x]&&R[x]){
            if (s[L[x]]<s[R[x]]){
                fo(i,x-s[L[x]],x-1)
                add(1,x,x+s[R[x]],a[x]/a[i]);
                add(1,x+1,x+s[R[x]],1);
            }
            else{
                fo(i,x+1,x+s[R[x]])
                add(1,x-s[L[x]],x,a[x]/a[i]);
                add(1,x-s[L[x]],x-1,1);
            }
        }
        else
            if (L[x]+R[x]){
                if (L[x])add(1,x-s[L[x]],x-1,1);
                else add(1,x+1,x+s[R[x]],1);
            }
    }
}

int getans(int x){
    int ans=0;
    while(x){
        ans+=tree[x];
        x-=x&-x;
    }
    return ans;
}

void change(int x){
    while(x<=n){
        tree[x]++;
        x+=x&-x;
    }
}

int main(){
    scanf("%d",&n);
    fo(i,1,n)scanf("%d",&a[i]);
    sta[k=1]=1;
    fo(i,2,n){
        if (a[i]<=a[sta[k]]){
            fa[i]=sta[k];
            sta[++k]=i;
            continue;
        }
        while(k&&a[sta[k]]<a[i])k--;
        fa[sta[k+1]]=i;
        fa[i]=sta[k];
        sta[++k]=i;
    }
    fo(i,1,n)
    if (!fa[i])rt=i;
    else{
        if (i<fa[i])L[fa[i]]=i;
        else R[fa[i]]=i;
    }
    bfs();
    fo(i,1,n)add(0,i,0,a[i]);
    sort(q+1,q+1+m);
    fo(i,1,m)
    if (q[i].ty)ans=ans+getans(q[i].r)-getans(q[i].l-1);
    else change(q[i].l);
    printf("%lld\n",ans);
    return 0;
}

方案2:

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}

const int N=500050;
const int LGN=20;
const int Q=N*LGN<<1;
int st[N][3];
int tp;
int vis[N];

struct query
{
    int x,a,sign;
}qs[Q];
bool operator<(query p,query q){return p.x<q.x;}

struct node
{
    int key,id;
}srt[N];

bool operator<(node x,node y){return x.key<y.key;}

int A[N],fa[N],son[N][2],stack[N],lab[N],num[N];
int n,q,top,root,idx;
LL ans;

inline int lowbit(int x){return x&-x;}

struct tree
{
    int num[N];

    void change(int x,int delta){for(;x<=idx;x+=lowbit(x)) num[x]+=delta;}

    int query(int x)
    {
        int ret=0;
        for (;x;x-=lowbit(x)) ret+=num[x];
        return ret;
    }
}t;

void build()
{
    for(int i=1;i<=n;i++)
    {
        while(top && A[stack[top]]<A[i])
        {
            fa[i]=stack[top-1];
            fa[son[i][0]]=stack[top];
            son[stack[top]][1]=son[i][0];
            son[i][0]=stack[top];
            fa[stack[top--]]=i;
        }
        if(top) son[stack[top]][1]=i;
        stack[++top]=i;
        fa[i]=stack[top-1];
        if(!fa[i]) root=i;
    }
}

void dfs()
{
    int x,l,r;
    st[++tp][0]=root;st[tp][1]=1;st[tp][2]=n;
    while(tp)
    {
        x=st[tp][0];
        l=st[tp][1];
        r=st[tp][2];
        if(!x)
        {
            tp--;
            continue;
        }
        if(!vis[x])
        {
            if(x-l<r-x)
                for(int i=l;i<=x;i++)
                {
                    qs[++q].x=r;qs[q].a=A[x]/A[i];qs[q].sign=1;
                    qs[++q].x=x;qs[q].a=A[x]/A[i];qs[q].sign=-1;
                    if(i<x&&A[i]==1)    ans++;
                }
            else
                for(int i=x;i<=r;i++)
                {
                    qs[++q].x=x-1;qs[q].a=A[x]/A[i];qs[q].sign=1;
                    qs[++q].x=l-1;qs[q].a=A[x]/A[i];qs[q].sign=-1;
                    if(i>x&&A[i]==1)    ans++;
                }
            vis[x]++;
        }
        else
        if(vis[x]==1)
        {
            vis[x]++;
            st[++tp][0]=son[x][0];st[tp][1]=l;st[tp][2]=x-1;
            continue;
        }
        else
        {
            vis[x]++;
            st[tp][0]=son[x][1];st[tp][1]=x+1;st[tp][2]=r;
        }
    }
}

void pre()
{
    for(int i=1;i<=n;i++)
    {
        srt[i].key=A[i];
        srt[i].id=i;
    }
    sort(srt+1,srt+1+n);
    idx=0;
    for(int i=1;i<=n;i++)
    {
        if(srt[i].key!=srt[i-1].key)    idx++;
        lab[srt[i].id]=idx;
        num[idx]=srt[i].key;
    }
}

int pos(int v)
{
    int l=1,r=idx,mid,ret=0;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(num[mid]<=v) l=(ret=mid)+1;
        else r=mid-1;
    }
    return ret;
}

void calc()
{
    sort(qs+1,qs+1+q);
    for(int cur=1,i=1;i<=q;i++)
    {
        while(cur<=n&&cur<=qs[i].x)
            t.change(lab[cur++],1);
        ans+=qs[i].sign*t.query(pos(qs[i].a));
    }
}

int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        A[i]=read();
    build();
    ans=0;
    dfs();
    pre();
    calc();
    printf("%lld\n",ans);
    return 0;
}

results matching ""

    No results matching ""