题解:洛谷 AT_abc440_c Striped Horse

【题目来源】

洛谷:AT_abc440_c [ABC440C] Striped Horse - 洛谷

【题目描述】

问题陈述

林格先生想给一匹马画上斑马纹。

\(N\) 个方格,编号为 \(1\)\(N\) 排列成一行。
初始时,所有方格都是白色的,将方格 \(i\) 涂成黑色的成本是 \(C_i\)

考虑执行下面的程序一次,将一些方格涂成黑色:

  • 自由选择一个正整数 \(x\)
  • 对于所有满足 \(1 \leq i \leq N\) 的整数 \(i\),若 \((i + x)\) 除以 \(2W\) 后的余数小于 \(W\),则将正方形 \(i\) 涂成黑色。

求执行此程序的最小总成本。

给你 \(T\) 个测试用例,请逐个求解。

【输入】

输入内容由标准输入法提供,格式如下,其中 \(\mathrm{case}_i\) 表示第 \(i\) 个测试用例。

\(T\)
\(\mathrm{case}_1\)
\(\vdots\)
\(\mathrm{case}_T\)

每个测试用例的格式如下:

\(N\) \(W\)
\(C_1\) \(\dots\) \(C_N\)

【输出】

输出 \(T\) 行。第 \(i\) 行应包含第 \(i\) 个测试用例的答案。

【输入样例】

4
8 2
1 10 10 1 1 10 10 1
8 3
1 10 10 1 1 10 10 1
8 4
1 10 10 1 1 10 10 1
4 100
100000 100000 100000 100000

【输出样例】

4
12
22
0

【核心思想】

  1. 问题分析\(N\) 个方格排成一行,初始白色,涂黑方格 \(i\) 的成本为 \(C_i\)。选择正整数 \(x\),将所有满足 \((i + x) \bmod 2W < W\) 的方格涂黑。求最小总成本。分析涂黑规则:\((i + x) \bmod 2W \in [0, W-1]\) 时涂黑,即 \(i + x \in [0, W-1] \cup [2W, 3W-1] \cup [4W, 5W-1] \cup \ldots\)(模 \(2W\) 意义下)。对于固定的 \(x\),涂黑的方格位置形成周期为 \(2W\) 的模式,每个周期内涂黑 \(W\) 个连续方格。这是一个周期性模式 + 前缀和优化问题,核心在于枚举所有可能的 \(x\) 对应的涂黑模式,用前缀和快速计算成本。

  2. 算法选择

    • 前缀和 + 滑动窗口:将问题转化为在扩展数组上滑动长度为 \(W\) 的窗口,窗口位置由 \(x\) 决定,用前缀和 \(O(1)\) 计算每个窗口的成本
    • 动态规划递推\(dp[i]\) 表示以位置 \(i\) 为窗口右端点时,覆盖到 \(i\) 的最小成本。利用周期性,\(dp[i] = dp[i-2W] + (sa[i] - sa[i-W])\)
  3. 关键步骤

    • 读入数据\(T\) 个测试用例,每个用例读入 \(N\)\(W\)\(C[1..N]\)
    • 数组扩展\(a[N+1..N+W] = 0\),处理边界情况
    • 前缀和计算\(sa[i] = sa[i-1] + a[i]\)\(1 \leq i \leq N+W\)
    • DP 递推\(i\)\(1\)\(N+W\)):
      • \(i > 2W\)\(dp[i] = dp[i-2W] + (sa[i] - sa[i-W])\)
      • \(i > W\)\(dp[i] = sa[i] - sa[i-W]\)
      • 否则:\(dp[i] = sa[i]\)
    • 答案提取\(ans = \min_{i \in [\max(1, N-W+1), N+W]} dp[i]\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(T \cdot (N+W))\),每个测试用例线性处理
    • 空间复杂度:\(O(N+W)\),扩展数组、前缀和数组和 DP 数组
  5. 周期性模式与前缀和优化的核心思想

    • 涂黑规则的周期性分析:对于固定 \(x\),方格 \(i\) 被涂黑当且仅当 \((i+x) \bmod 2W < W\)。这意味着涂黑方格以 \(2W\) 为周期,每个周期内涂黑 \(W\) 个连续方格(如位置 \(p, p+1, \ldots, p+W-1\)),跳过 \(W\) 个方格,再涂黑 \(W\) 个,如此循环
    • \(x\) 与窗口位置的对应\(x\) 的选择决定了第一个涂黑窗口的起始位置。不同的 \(x\) 对应不同的相位,但本质上都是在周期为 \(2W\) 的序列上选择涂黑 \(W\) 个、跳过 \(W\) 个的模式
    • DP 的周期递推\(dp[i]\) 表示覆盖到位置 \(i\) 的最小成本。由于周期为 \(2W\),位置 \(i\) 的涂黑窗口与位置 \(i-2W\) 的窗口属于不同的周期但模式相同,因此 \(dp[i] = dp[i-2W] + \text{当前周期窗口成本}\)
    • 边界处理:数组扩展 \(W\)\(0\),确保最后一个不完整的周期也能被正确处理。答案在 \([N-W+1, N+W]\) 范围内取最小值,覆盖所有可能的结束位置
    • 适用于周期性模式匹配、滑动窗口成本计算、前缀和优化类问题

【算法标签】

普及 #前缀和

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005 * 2;
int T, n, a[N], w, sa[N], dp[N];

signed main()
{
    cin >> T;
    while (T--)
    {
        cin >> n >> w;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = n + 1; i <= n + w; i++)
            a[i] = 0;  // 扩展数组,填充0

        // 计算前缀和
        for (int i = 1; i <= n + w; i++)
            sa[i] = sa[i-1] + a[i];

        // 动态规划
        for (int i = 1; i <= n + w; i++)
        {
            if (i > 2 * w)
                dp[i] = dp[i - 2 * w] + (sa[i] - sa[i - w]);
            else if (i > w)
                dp[i] = (sa[i] - sa[i - w]);
            else
                dp[i] = sa[i];
        }

        // 寻找最小值
        int ans = 1e18;
        for (int i = max(1LL, n - w + 1); i <= n + w; i++)
            ans = min(ans, dp[i]);
        cout << ans << endl;
    }
    return 0;
}

【运行结果】

8 2
1 10 10 1 1 10 10 1
4
8 3
1 10 10 1 1 10 10 1
12
8 4
1 10 10 1 1 10 10 1
22
4 100
100000 100000 100000 100000
0
posted @ 2026-08-27 11:05  团爸讲算法  阅读(6)  评论(0)    收藏  举报