Skip to main content
Back to problems
#3395
Hard Algorithms

Subsequences with a unique middle mode i

Array Hash Table Math Combinatorics
20.9% acceptance
Feb 24, 2026
24
25
Given an integer array nums, find the number of subsequences of size 5 of nums with a unique middle mode. Since the answer may be very large, return it modulo 10^9 + 7. A mode is the element that appears the maximum number of times. A sequence of size 5 contains a unique middle mode if the middle element (seq[2]) is a unique mode.

Solution

Rust
Time O(n³)
Space O(n)
LeetCode
solution.rs
impl Solution {
  pub fn subsequences_with_middle_mode(nums: Vec<i32>) -> i32 {
    // For each position m as the "middle" of a size-5 subsequence:
    //   v = nums[m], lv = count of v to the left, rv = count of v to the right
    //   ll = m (total positions left), rr = n-m-1 (total positions right)
    //   nl = ll - lv (non-v left count), nr = rr - rv (non-v right count)
    //
    // We choose 2 from left and 2 from right. Let vl (resp vr) = # of v chosen from left (right).
    // vl in 0..=min(lv,2), vr in 0..=min(rv,2), and we choose (2-vl) non-v from left, (2-vr) from right.
    //
    // A subsequence is valid (v is unique mode) iff freq(v) > freq(any other value).
    // Total freq(v) = 1 + vl + vr.
    //
    // Case vl+vr >= 2 (freq(v) >= 3): any other value appears at most 2 < 3 → always valid.
    // Case vl+vr == 1 (freq(v) == 2): valid iff no non-v value appears >= 2 times
    //   i.e., the 3 non-v elements chosen are all distinct values.
    // Case vl+vr == 0 (freq(v) == 1): NOT valid (4 non-v elements can't all be distinct
    //   in a way that none appears >= 1 = freq(v)... actually valid iff all 4 non-v distinct,
    //   but then freq(v)=1=max and v is unique mode. However freq=1 for all, so v IS the mode
    //   only if all others appear <= 1 time. With 4 elements all distinct, everyone has freq=1
    //   including v, so v is NOT the unique mode (tied). So vl+vr=0 → never valid.
    
    let n = nums.len();
    let md = 1_000_000_007i64;
    let inv2 = 500_000_004i64;
    
    let c2 = |x: i64| -> i64 {
      if x < 2 { 0 } else { x % md * ((x - 1) % md) % md * inv2 % md }
    };
    let c_k = |x: i64, k: i64| -> i64 {
      if k < 0 || x < k { return 0; }
      match k {
        0 => 1,
        1 => x % md,
        2 => { if x < 2 { 0 } else { x % md * ((x-1) % md) % md * inv2 % md } }
        _ => 0,
      }
    };

    use std::collections::HashMap;
    let mut left_cnt: HashMap<i32, i64> = HashMap::new();
    let mut right_cnt: HashMap<i32, i64> = HashMap::new();
    for &x in &nums {
      *right_cnt.entry(x).or_insert(0) += 1;
    }

    let mut ans = 0i64;

    for m in 0..n {
      let v = nums[m];
      // Move v from right to current (middle)
      *right_cnt.get_mut(&v).unwrap() -= 1;

      let lv = *left_cnt.get(&v).unwrap_or(&0);
      let rv = *right_cnt.get(&v).unwrap_or(&0);
      let ll = m as i64;
      let rr = (n - m - 1) as i64;
      let nl = ll - lv;
      let nr = rr - rv;

      // Sum for vl+vr >= 2: always valid
      let mut ways_ge2 = 0i64;
      for vl in 0i64..=lv.min(2) {
        for vr in 0i64..=rv.min(2) {
          if vl + vr < 2 { continue; }
          let left_nv = 2 - vl;
          let right_nv = 2 - vr;
          let w = c_k(lv, vl) * c_k(rv, vr) % md
               * c_k(nl, left_nv) % md
               * c_k(nr, right_nv) % md;
          ways_ge2 = (ways_ge2 + w) % md;
        }
      }

      // Sum for vl+vr == 1: valid iff 3 non-v chosen are all distinct values
      // Case A: vl=1, vr=0 → choose 1 non-v from left, 2 non-v from right, all distinct in values
      // Case B: vl=0, vr=1 → choose 2 non-v from left, 1 non-v from right, all distinct
      
      // For case A: ways = lv * (# pairs: 1 from nl, 2-unordered from nr, all 3 distinct)
      // = lv * [nl*C(nr,2) - sum_{u≠v} lu * C(ru,2)   (pairs with same value on right)
      //                    - sum_{u≠v} lu * ru * (nr - ru)  ... NO
      // 
      // Actually: # (a, {b,c}) with a in left-nonv, {b,c} ⊆ right-nonv, all 3 from distinct values
      // = nl*C(nr,2) - # where b=c (both right same value) - # where a=b or a=c (but b≠c)
      // Wait, "distinct values" means val(a)≠val(b), val(a)≠val(c), val(b)≠val(c).
      // Bad events: val(b)=val(c) OR val(a)=val(b) OR val(a)=val(c).
      // These overlap. Let's use inclusion-exclusion:
      // |A or B or C| = |val(b)=val(c)| + |val(a)=val(b)| + |val(a)=val(c)| - ... (triples overlap)
      // 
      // |val(b)=val(c)|: sum_{u≠v} C(ru,2) * nl = sc2r * nl
      // |val(a)=val(b)| (unordered pair, so val(a) matches one of {b,c}):
      //   = sum_{u≠v} lu * ru * (nr - 1)  ... NO, we're choosing unordered {b,c}
      //   If val(a)=u and one of {b,c}=u: choose a=u (lu ways), choose one of right pair as u (ru ways), choose other right nonv (nr-1 ways). But this counts ordered pairs. For unordered: divide by... no.
      //   Better: # (a, {b,c}): val(a)=u, u ∈ {b,c}, b≠c.
      //   = sum_u lu * [ru * (nr - ru)] (choose a=u: lu ways; choose one right as u: ru ways; choose other right nonv ≠ u: nr-ru ways)
      //   But this overcounts: if both b=u (then val(b)=u=val(a) AND b=c is handled separately)
      //   Actually the set {b,c} must have at least one element = u. Let val(b)=u OR val(c)=u (unordered).
      //   = sum_u lu * [C(ru,1)*(nr-ru) + C(ru,2)] -- wait this mixes two bad events.
      //
      // This inclusion-exclusion is getting complicated. Let me try a direct formula:
      // # valid = # (a, {b,c}): a from left-nonv, {b,c} from right-nonv, all 3 values distinct
      // = C(nl,1)*C(nr,2) - [# where a's value in right pair's values]
      //                   - [# where right pair has same value]
      //                   + [# where a's value in right pair AND right pair same value]
      //   The last term: a=u, b=c=u → lu * C(ru,2). Sum = sum_u lu*C(ru,2) = SumLuC2Ru.
      //   Middle term 2: sum_u C(ru,2) * nl = sc2r_total * nl... NO, nl is total not per-u.
      //   
      // Actually let me just define SumCross = sum_{u≠v} lu*ru.
      // 
      // # valid_A = nl * C(nr,2) 
      //           - sum_u lu * C(ru,1) * (nr - ru)   [a=u, one right = u, other right ≠ u]  
      //           - sum_u lu * C(ru,2)               [a=u, both right = u]
      //           - sum_u C(ru,2) * (nl - lu)         [right pair same value u, a ≠ u]
      //   Hmm (last two combine as sc2r*nl).
      // 
      // Let me try differently: 
      // # valid_A = nl*C(nr,2) - [# where right pair NOT all distinct (same value)]
      //                        - [# where a's value appears in right pair (a=u, one or both of {b,c}=u)]
      //           + [# where both: right pair same value AND a=same u]
      //         = nl*C(nr,2) - sc2r * nl - sum_u lu * (C(ru,1)*(nr-ru) + C(ru,2)) + sum_u lu*C(ru,2)
      //         Wait: sum_u lu * C(ru,1)*(nr-ru) counts (a=u, one right=u, other right≠u).
      //               sum_u lu * C(ru,2) counts (a=u, both right=u).
      //               Total a=u appearing in right: sum_u lu * (ru*(nr-ru) + C(ru,2))
      //                                           = sum_u lu * (ru*(nr-ru) + ru*(ru-1)/2)
      //                                           = sum_u lu * ru * (nr - ru + (ru-1)/2)...
      //             This gets messy with integer division.
      //
      // Cleaner: # valid_A = (total) - (bad where same value appears twice or more)
      // Among (a, b, c) where a∈left_nonv[position], b∈right_nonv[pos], c∈right_nonv[pos], b<c (positions):
      // bad event: val(a)=val(b) OR val(a)=val(c) OR val(b)=val(c)
      // = sum_u [lu * (ru choose 1) * (nr - 1) - ...] 
      //
      // I'll just compute it as: 
      // # where val(b)=val(c): nl * sum_u C(ru,2) = nl * sc2r
      // # where val(a)=val(b) AND val(b)!=val(c): sum_u lu*ru*(nr-ru)
      // # where val(a)=val(c) AND val(c)!=val(b): same = sum_u lu*ru*(nr-ru) [by symmetry]
      // # where val(a)=val(b)=val(c): sum_u lu*C(ru,2)
      // 
      // These are disjoint events (a's value matches left, or right pair same, or mixed).
      // Wait they're NOT disjoint:
      //   val(a)=val(b) AND val(b)=val(c) IS possible (val(a)=val(b)=val(c)).
      //   This is covered in "val(a)=val(b) AND val(b)!=val(c)" + "val(a)=val(b)=val(c)".
      // Let me define:
      //   E1 = val(b)=val(c) [right pair same value]
      //   E2 = val(a) equals any of {val(b), val(c)} [left value in right pair]
      // 
      // # bad = |E1 ∪ E2| = |E1| + |E2| - |E1 ∩ E2|
      // |E1| = nl * sc2r  (for any a in left_nonv, right pair same value)
      // |E2| = sum_u lu * (# pairs {b,c} where u ∈ {val(b),val(c)})
      //      = sum_u lu * [ru*(nr-ru) + C(ru,2)] = sum_u lu * [ru*nr - ru^2 + C(ru,2)]
      //      Hmm: ru*(nr-ru) = # pairs where exactly one b or c = u; C(ru,2) = both are u.
      //      So sum_u lu * [ru*(nr-ru) + C(ru,2)] counts pairs with at least one = u.
      //      = sum_u lu * [nr*ru - C(ru,2) - ... ] 
      //        Actually # pairs from nr items with at least one = u = C(nr,2) - C(nr-ru,2)
      //        = C(nr,2) - C(nr-ru,2).
      //      |E2| = sum_u lu * [C(nr,2) - C(nr-ru, 2)]
      // |E1 ∩ E2| = sum_u lu * C(ru,2)  (right pair same u, left = u)
      //
      // # valid_A = nl*C(nr,2) - nl*sc2r - sum_u lu*[C(nr,2)-C(nr-ru,2)] + sum_u lu*C(ru,2)
      //
      // This is O(n^2) total since we iterate over all unique u values at each middle m.
      // 
      // For simplicity, precompute at each m:
      //   sc2r = sum_u C(ru,2)
      //   sc2l = sum_u C(lu,2)
      //   sum_lu_c2_nr_minus_ru = sum_u lu * C(nr-ru, 2)  -- HARD to compute without iterating
      //
      // Given n ≤ 1000, O(n^2) is fine. Just iterate over all u at each m.

      let all_vals: std::collections::HashSet<i32> =
        left_cnt.keys().chain(right_cnt.keys()).cloned().collect();
      
      let mut sc2l = 0i64;
      let mut sc2r = 0i64;
      let mut sum_lu_c2_nr_ru = 0i64; // sum_u lu * C(nr-ru, 2)
      let mut sum_rv_c2_nl_lu = 0i64; // sum_u ru * C(nl-lu, 2)
      let mut sum_lu_c2_ru = 0i64;    // sum_u lu * C(ru, 2)
      let mut sum_ru_c2_lu = 0i64;    // sum_u ru * C(lu, 2)

      for u in &all_vals {
        if *u == v { continue; }
        let lu = *left_cnt.get(u).unwrap_or(&0);
        let ru = *right_cnt.get(u).unwrap_or(&0);
        sc2l = (sc2l + c2(lu)) % md;
        sc2r = (sc2r + c2(ru)) % md;
        sum_lu_c2_nr_ru = (sum_lu_c2_nr_ru + lu % md * c2(nr - ru) % md) % md;
        sum_rv_c2_nl_lu = (sum_rv_c2_nl_lu + ru % md * c2(nl - lu) % md) % md;
        sum_lu_c2_ru = (sum_lu_c2_ru + lu % md * c2(ru) % md) % md;
        sum_ru_c2_lu = (sum_ru_c2_lu + ru % md * c2(lu) % md) % md;
      }

      // Case A: vl=1, vr=0. ways = lv * valid_A
      // valid_A = nl*C(nr,2) - nl*sc2r - sum_u lu*[C(nr,2)-C(nr-ru,2)] + sum_u lu*C(ru,2)
      //         = nl*C(nr,2) - nl*sc2r - sum_u lu*C(nr,2) + sum_lu_c2_nr_ru + sum_lu_c2_ru
      //         = (nl - sum_lu)*C(nr,2) - nl*sc2r + sum_lu_c2_nr_ru + sum_lu_c2_ru
      //   wait: sum_u lu = nl. And sum_u lu * C(nr,2) = nl * C(nr,2).
      //         = nl*C(nr,2) - nl*sc2r - nl*C(nr,2) + sum_lu_c2_nr_ru + sum_lu_c2_ru
      //         = -nl*sc2r + sum_lu_c2_nr_ru + sum_lu_c2_ru
      let c_nr_2 = c2(nr);
      let c_nl_2 = c2(nl);
      let valid_a = (md + md - nl % md * sc2r % md % md + sum_lu_c2_nr_ru + sum_lu_c2_ru) % md;
      let ways_v1_a = lv % md * valid_a % md;

      // Case B: vl=0, vr=1. ways = rv * valid_B (symmetric)
      // valid_B = nr*C(nl,2) - nr*sc2l - nr*C(nl,2) + sum_ru_c2_nl_lu + sum_ru_c2_lu
      //         = -nr*sc2l + sum_rv_c2_nl_lu + sum_ru_c2_lu
      let valid_b = (md + md - nr % md * sc2l % md % md + sum_rv_c2_nl_lu + sum_ru_c2_lu) % md;
      let ways_v1_b = rv % md * valid_b % md;

      let _ = (c_nr_2, c_nl_2); // silence unused warnings

      ans = (ans + ways_ge2 + ways_v1_a + ways_v1_b) % md;

      *left_cnt.entry(v).or_insert(0) += 1;
    }

    ans as i32
  }
}