1 条题解

  • 0
    @ 2026-10-31 17:58:14

    思路

    要统计满足 ai:aj:ak=7:5:3a_i:a_j:a_k=7:5:3、且数值为 5x5x 的那个位置在三点中最小或最大的三元组。

    设数值 5x5x 的位置为 jj。另外两个位置分别是 7x7x 和 3x3x。“jj 最小或最大”排除了 5x5x 在中间的情况,剩下的合法顺序只有四种:

    • 5x→3x→7x5x\to3x\to7x(5x5x 最左)
    • 5x→7x→3x5x\to7x\to3x(5x5x 最左)
    • 3x→7x→5x3x\to7x\to5x(5x5x 最右)
    • 7x→3x→5x7x\to3x\to5x(5x5x 最右)

    统计时分两个方向做:

    从右往左扫描 —— 已统计的元素都在当前元素右侧,于是可以统计 5x5x 位于下标最大处(最右)的两种顺序:

    • c__5[x]:右侧出现过的 5x5x 个数;
    • c_75[x]:右侧已形成的 7x→5x7x\to5x 二元组个数;
    • c_35[x]:右侧已形成的 3x→5x3x\to5x 二元组个数;
    • c735[x]、c375[x]:已凑成的 7x→3x→5x7x\to3x\to5x、3x→7x→5x3x\to7x\to5x 三元组个数。

    遇到 7x7x 时:先用 c_35 把它补成三元组(7x→3x→5x7x\to3x\to5x),再把当前 7x7x 与右侧的 5x5x 组成新的二元组(7x→5x7x\to5x)。 遇到 3x3x 时:先用 c_75 把它补成三元组(3x→7x→5x3x\to7x\to5x),再与右侧的 5x5x 组成新的二元组(3x→5x3x\to5x)。

    从左往右扫描同理,统计 5x5x 位于下标最小处(最左)的两种顺序,对应 c537(5x→3x→7x5x\to3x\to7x)与 c573(5x→7x→3x5x\to7x\to3x),二元组为 c53_(5x→3x5x\to3x)和 c57_(5x→7x5x\to7x)。

    最后把四种三元组的计数相加即为答案。

    注意:

    • 一个数可能同时是 5x5x、7x7x、3x3x(例如 105=5⋅21=7⋅15=3⋅35105=5\cdot21=7\cdot15=3\cdot35),代码中三个 if 是独立的、互不 else,因此可以分别扮演三种角色。
    • 结果最大约为 C(3×105,3)≈4.5×1015C(3\times10^5,3)\approx4.5\times10^{15},超出 32 位整数,代码用 #define int long long。

    复杂度: 时间 O(nlog⁡n)O(n\log n)(map 每次操作对数级),空间 O(n)O(n)。

    代码

    #include<bits/stdc++.h>
    #define int long long
    #define dd double
    #define str string
    #define el cout << '\n'
    #define re return
    #define ff first
    #define ss second
    #define pll pair<int,int>
    #define pdd pair<dd,dd>
    #define all(x) x.begin(),x.end()
    #define pb push_back
    using namespace std;
    
    void go(){
        int n;cin>>n;
        vector<int>a(n+1, 0);
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
    
        // 从右向左扫描:统计 5x 位于最右侧的两种顺序
        // 键 x 表示同比例的一组数 (3x, 5x, 7x)
        map<int, int>c__5, c_35, c735, c_75, c375;
    
        for(int i=n;i>0;i--){
            // 当前数是 5x,右侧所有 5x 都能和它配对
            if(a[i]%5==0){
                c__5[a[i]/5]++;
            }
            if(a[i]%7==0){               // 当前数是 7x
                c735[a[i]/7] += c_35[a[i]/7];   // 7x + (3x→5x) 凑成 7x→3x→5x
                c_75[a[i]/7] += c__5[a[i]/7];   // 7x 与右侧的 5x 组成新二元组
            }
            if(a[i]%3==0){               // 当前数是 3x
                c375[a[i]/3] += c_75[a[i]/3];   // 3x + (7x→5x) 凑成 3x→7x→5x
                c_35[a[i]/3] += c__5[a[i]/3];   // 3x 与右侧的 5x 组成新二元组
            }
        }
    
        // 从左向右扫描:统计 5x 位于最左侧的两种顺序
        map<int, int>c5__, c53_, c537, c57_, c573;
    
        for(int i=1;i<=n;i++){
            if(a[i]%5==0){
                c5__[a[i]/5]++;
            }
            if(a[i]%7==0){
                c537[a[i]/7] += c53_[a[i]/7];   // (5x→3x) + 7x 凑成 5x→3x→7x
                c57_[a[i]/7] += c5__[a[i]/7];   // 5x→7x 二元组
            }
            if(a[i]%3==0){
                c573[a[i]/3] += c57_[a[i]/3];   // (5x→7x) + 3x 凑成 5x→7x→3x
                c53_[a[i]/3] += c5__[a[i]/3];   // 5x→3x 二元组
            }
        }
    
        // 四种顺序的三元组计数之和
        int ans = 0;
        for(auto [num, cnt]:c375){ans += cnt;}
        for(auto [num, cnt]:c735){ans += cnt;}
        for(auto [num, cnt]:c537){ans += cnt;}
        for(auto [num, cnt]:c573){ans += cnt;}
    
        cout<<ans;el;
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int _=1;                         // 本题只有单组数据
        while(_--){
            go();
        }
        return 0;
    }
    
    • 1

    信息

    ID
    21
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者