C ++インクリメントトリプル(列挙、プレフィックス合計)

3つの整数配列
A = [A1、A2、…AN]、
B = [B1、B2、…BN]、
C = [C1、C2、…CN]が与えられた場合、トリプルの数を数えてください(i 、j、k)
は次の条件を満たす:
1≤i、j、k≤NAi
<Bj <Ck
入力フォーマット
最初の行には整数Nが含まれている。2行目には、N個の整数A1、A2、... ANが含まれています。3行目には、N個の整数B1、B2、... BNが含まれています。
4行目には、N個の整数C1、C2、... CNが含まれています。
出力形式
整数は答えを表します。
データ範囲
1≤N≤105,0≤Ai、Bi、Ci≤105
入力例:
3
1 1 1
2 2 2
3 3 3
出力例:
27

この質問の鍵は、各増分トリプルのa [i]とc [k]がb [j]によってバインドされていることを見つけることです。したがって、トリプルの数はb [j]を列挙して計算する必要があります。同時に、この質問のエラーが発生しやすいポイントは、各値の出現回数をカウントするときであり、最後の要素の添え字はデータの最大値によって決定され、データ範囲の最大値が均一に使用されます。
ACコード:

#include<stdio.h>
#include<string.h>

const int N=100010;
typedef long long LL;

int n;
int a[N],b[N],c[N];
int cnt[N],s[N];
int anum[N],cnum[N];

int main()
{
    
    
    scanf("%d",&n);
    //因为要计算值出现次数的前缀和,把所有值+1避免占用0下标
    for(int i=1;i<=n;++i){
    
    scanf("%d",&a[i]);++a[i];}
    for(int i=1;i<=n;++i){
    
    scanf("%d",&b[i]);++b[i];}
    for(int i=1;i<=n;++i){
    
    scanf("%d",&c[i]);++c[i];}

    //统计a数组中各个值出现的次数
    for(int i=1;i<=n;++i) ++cnt[a[i]];
    //计算a数组中各个值出现次数的前缀和
    //因为值的范围是1~100001,cnt的最后一项为cnt[100001]
    for(int i=1;i<N;++i) s[i]=s[i-1]+cnt[i];
    //anum[i]中保存a中小于b[i]的数的个数
    for(int i=1;i<=n;++i) anum[i]=s[b[i]-1];

    memset(cnt,0,sizeof(cnt));
    memset(s,0,sizeof(s));
    for(int i=1;i<=n;++i) ++cnt[c[i]];
    for(int i=1;i<N;++i) s[i]=s[i-1]+cnt[i];
    //cnum[i]中保存c中大于b[i]的数的个数
    for(int i=1;i<=n;++i) cnum[i]=s[N-1]-s[b[i]];

    LL ans=0;//统计答案
    for(int i=1;i<=n;++i) ans+=(LL)anum[i]*cnum[i];

    printf("%lld",ans);
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_44643644/article/details/108854432