Three Arrays Gym - 101741A(区间枚举+二分)

Three Arrays Gym - 101741A (区间枚举+二分)

Problem Description

You are given three arrays: a containing na elements, b containing nb elements and c containing nc elements. These arrays are sorted in non-decreasing order: that is, for every i such that 1 ≤ i < na we have ai ≤ ai + 1, for every j such that 1 ≤ j < nb we have bj ≤ bj + 1, and for every k such that 1 ≤ k < nc we have ck ≤ ck + 1.

Your task is to calculate the number of triples (i, j, k) such that |ai - bj| ≤ d, |ai - ck| ≤ d, and |bj - ck| ≤ d.

Input

The input contains one or more test cases. Each test case consists of four lines.

The first line of each test case contains four integers: d, na, nb, and nc (1 ≤ d ≤ 1e9, 1 ≤ na, nb, nc ≤ 5·1e5).

The second line contains na integers a1, a2, …, ana: the array a ( - 1e9 ≤ ai ≤ 1e9).

The third line contains nb integers b1, b2, …, bnb: the array b ( - 1e9 ≤ bi ≤ 1e9).

The fourth line contains nc integers c1, c2, …, cnc: the array c ( - 1e9 ≤ ci ≤ 1e9).

All arrays are sorted in non-decreasing order. The total sum of na over all testcases does not exceed 5·105. The total sum of nb over all testcases does not exceed 5·105. The total sum of all nc over all testcases does not exceed 5·105. The test cases just follow one another without any special separators.

Output

For each test case, print a single integer: the number of triples (i, j, k) such that |ai - bj| ≤ d, |ai - ck| ≤ d, and |bj - ck| ≤ d.

Example

Input

1 3 3 3
1 2 3
1 2 3
1 2 3
1 6 6 6
1 1 2 2 3 3
2 2 3 3 4 4
3 3 4 4 5 5

Output

15
56

题意

有三个长度为N的有序序列,问有多少对(i,j,k)满足
|aibj|d,|aick|d,and|bjck|d | a i   −   b j |   ≤   d , | a i   −   c k |   ≤   d , a n d | b j   −   c k |   ≤   d .
1<=N<=51e5<=d<=1e91e9<=aibici<=1e9 1 <= N <= 5 ∗ 1 e 5 , <= d <= 1 e 9 , − 1 e 9 <= a i , b i , c i <= 1 e 9

思路

很明显N很大,暴力三层循环N^3,时间复杂度很高
这时就要想办法把三维循环降下来等来降低时间复杂度
考虑把三个序列合并,之后枚举长度 d d <script type="math/tex" id="MathJax-Element-3">d</script>,把区间中为原序列A、B、C的个数相乘即为答案
(还要减去前面区间重复计算的部分,在找区间d时,序列的端点用二分)

AC代码

#include <bits/stdc++.h>
using namespace std;
#define maxn 1500010
typedef long long ll;
typedef struct node{
    ll w;
    int id;  //ID=1、2、3分别代表原来的A、B、C里的序列
}node;
node p[maxn];
int n, sum[4][maxn];  //sum[id][pos]代表从第一个位置到第pos位置,序列为id的个数
bool cmp(node aa, node bb)  //按权值排序
{
    return aa.w<bb.w;
}
int f(ll k)  //二分
{
    int mid,left=1,right=n;
    while(left<=right){
        mid=(left+right)/2;
        if(p[mid].w<=k){
            left=mid+1;
        }
        else right=mid-1;
    }
    return left;
}
int main()
{
    int na,nb,nc;
    ll d;
    while(scanf("%lld %d %d %d", &d,&na,&nb,&nc)!=EOF){
        int i;
        for(i=1;i<=na;i++){
            scanf("%lld", &p[i].w);
            p[i].id=1;
        }
        for(i=na+1;i<=na+nb;i++){
            scanf("%lld", &p[i].w);
            p[i].id=2;
        }
        for(i=na+nb+1;i<=na+nb+nc;i++){
            scanf("%lld", &p[i].w);
            p[i].id=3;
        }
        n=na+nb+nc;
        sort(p+1,p+1+n,cmp);
        sum[1][0]=sum[2][0]=sum[3][0]=0; //初始化
        for(i=1;i<=n;i++){  //统计前缀和
            if(p[i].id==1){
                sum[1][i]=sum[1][i-1]+1;
                sum[2][i]=sum[2][i-1];
                sum[3][i]=sum[3][i-1];
            }
            else if(p[i].id==2){
                sum[1][i]=sum[1][i-1];
                sum[2][i]=sum[2][i-1]+1;
                sum[3][i]=sum[3][i-1];
            }
            else if(p[i].id==3){
                sum[1][i]=sum[1][i-1];
                sum[2][i]=sum[2][i-1];
                sum[3][i]=sum[3][i-1]+1;
            }
        }
        ll ans=0;
        int left,right, _right=0;  //_right、right分别代表上次端点和当前端点的pos位置
        ll aa,bb,cc,_aa,_bb,_cc;
        ll k;
        for(i=1;i<=n;i++){
            k=p[i].w+d;
            left=i;
            right=f(k);  //手动写的二分,,,嗷嗷
            if(right>n)
                right--;
            if(p[right].w>k)
                right--;  
            //printf("i:%d right:%d\n", i,right);
            aa=sum[1][right]-sum[1][left-1];
            bb=sum[2][right]-sum[2][left-1];
            cc=sum[3][right]-sum[3][left-1];
            _aa=sum[1][_right]-sum[1][left-1];
            _bb=sum[2][_right]-sum[2][left-1];
            _cc=sum[3][_right]-sum[3][left-1];
            _right=right;
            ans+=(aa*bb*cc-_aa*_bb*_cc);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值