my-love-for-tomorrow

导航

【题解】雪人三元组统计问题(循环移位 + 条件拆分优化)

题目大意

给定三个长度为 n 的循环数组 a、b、c(循环数组指元素可循环访问,如 a[n] 等价于 a[0]),统计合法三元组 (i, j, k) 的数量,满足:对所有 t ∈ [0, n-1],均有 a[(i + t) % n] < b[(j + t) % n] < c[(k + t) % n]。其中 i, j, k 为数组的起始下标(范围 0 ≤ i,j,k < n),多组测试用例输入。

解题思路

1. 暴力解法(瓶颈分析)

暴力思路:枚举所有可能的三元组 (i, j, k)(共 n³ 种),对每个三元组遍历 n 个位置验证 a < b < c 的条件。复杂度分析:时间复杂度为 O(t * n⁴)(t 为测试用例数),当 n 达到 5000 时,n⁴ 是天文数字(约 6.25×10¹⁷),完全无法通过时间限制。

2. 第一次优化:循环移位等价性

  1. 核心观察
    三元组 (i, j, k) 与 (i - (j-1) mod n, 1, k - (j-1) mod n) 是等价的:
    循环数组的特性决定了,将 j 固定为 1 时,只需将 i 和 k 同步移位(模 n),得到的雪人序列仅循环顺序改变,a < b < c 的条件是否满足完全不变。
    因此,所有 j ≠ 1 的情况均可映射到 j = 1 的情况,只需计算 j = 1 时的合法 (i, k) 对数,最终结果乘以 n(覆盖 j 的 n 种选择)。
  2. 复杂度优化
    枚举量从 n³ 降至 n²,验证每个 (i, k) 仍需 n 次,时间复杂度优化为 O(t * n³),但 n=5000 时 n³=1.25×10¹¹,仍超时。

3. 第二次优化:条件独立性拆分

  1. 核心观察
    i 和 k 的合法性是相互独立的:
    合法 i 的条件:仅与 a 和 b 相关,即对所有 t,a[(i + t) % n] < b[t](j=1 时 b[(j + t) % n] = b[t]);
    合法 k 的条件:仅与 b 和 c 相关,即对所有 t,c[(k + t) % n] > b[t];
  2. 优化逻辑
    单独统计 j=1 时合法 i 的数量(记为 cnt_i);
    单独统计 j=1 时合法 k 的数量(记为 cnt_k);
    最终答案 = cnt_i * cnt_k * n(*n 对应 j 的所有可能)。
  3. 复杂度优化
    时间复杂度降至 O(t * n²),n=5000 时 n²=25×10⁶,完全满足时间限制。

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

void solve() {
    int n;
    cin >> n;
    // 初始化三个循环数组,长度为n
    vector<int> a(n), b(n), c(n);
    for (auto &x : a) cin >> x;
    for (auto &x : b) cin >> x;
    for (auto &x : c) cin >> x;
    
    // cnt_i:j=1时合法i的数量;cnt_k:j=1时合法k的数量
    LL cnt_i = 0, cnt_k = 0;

    // 统计合法的i:所有t满足a[(i+t)%n] < b[t]
    for (int i = 0; i < n; i++) {
        bool valid = true;
        for (int step = 0; step < n; step++) {
            // 循环访问a的第(i+step)个元素(模n实现循环)
            if (a[(i + step) % n] >= b[step]) {
                valid = false;
                break; // 提前退出,减少无效计算
            }
        }
        if (valid) cnt_i++;
    }

    // 统计合法的k:所有t满足c[(k+t)%n] > b[t]
    for (int k = 0; k < n; k++) {
        bool valid = true;
        for (int step = 0; step < n; step++) {
            if (c[(k + step) % n] <= b[step]) {
                valid = false;
                break;
            }
        }
        if (valid) cnt_k++;
    }

    // 最终答案:合法(i,k)对数 * n(覆盖j的所有选择)
    cout << cnt_i * cnt_k * n << "\n";
}

int main() {
    // 关闭cin/cout同步,提升输入输出效率(处理大数据量必备)
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) solve();

    return 0;
}

posted on 2026-01-25 19:20  lQvQe  阅读(0)  评论(0)    收藏  举报