环形数组上的滑动窗口,取模题型trick abc440_c C - Striped Horse

https://atcoder.jp/contests/abc440/tasks/abc440_c

思路:

1. 核心数学转化:从"下标"到"余数"

题目的涂色条件是:当 (i+x) mod 2W < W时,涂黑第 i 个方格。

我们可以将这个不等式理解为:对于一个固定的 x,凡是 i mod 2W 落在某个特定范围内的方格都会被涂黑。在一个周期 2W 内,满足条件的余数恰好有 W 个。由于 x 是可以自由选择的正整数,这 W 个余数在模 2W 的意义下是连续 的。 我们的目标是找到模 2W 的 2W 个余数中,连续的 W 个余数,使得这些余数对应的方格成本之和最小。

第一步:压缩(Mapping)
复制代码
vector<ll> a(n+1), vec(4*w);
rep(i,1,n) {
    cin>>a[i];
    vec[i%(2*w)]+=a[i]; // 将方格成本按余数分类累加
}
  • 方格数量 N 可能很大,但余数只有 2W 个。vec[r] 存储了所有满足 的方格之和。这一步将 的空间复杂度压缩到了
第二步:断环成链
复制代码
rep(i,2*w, 4*w-1) vec[i] = vec[i-2*w];
  • 因为余数是环状的(例如 的下一个余数是 0),为了方便处理"跨越边界"的连续区间,代码将 vec 数组复制了一份接在后面。这样,任何在环上连续的 W 个元素,在长度为 4W 的线性数组中都会表现为一段普通的连续区间。
第三步:滑动窗口
复制代码
ll ans=INF, tt=0;
ll l=0, r=-1;
while (r < 4*w) {
    while (r-l+1 < w) tt += vec[++r]; // 窗口不足 W,向右扩展
    ans = min(ans, tt);               // 更新当前窗口的最小和
    if (r == 4*w-1) break;
    tt -= vec[l++];                   // 窗口左端向右移,准备下一次滑动
}
  • 这是一个标准的双指针滑动窗口。窗口长度始终保持为 W。tt 维护当前窗口内余数成本的总和。遍历过程中,ans 会记录下所有可能的 W 长度区间中的最小值。

完整ac代码:

复制代码
void solve() {
    ll n,w;cin>>n>>w;
    vector<ll>a(n+1),vec(4*w);
    rep(i,1,n) {
        cin>>a[i];
        vec[i%(2*w)]+=a[i];
    }
    rep(i,2*w,4*w-1)vec[i]=vec[i-2*w];
    ll ans=INF,tt=0;
    ll l=0,r=-1;
    while (r<4*w) {
        while (r-l+1<w)tt+=vec[++r];
        ans=min(ans,tt);
        if (r==4*w-1)break;
        tt-=vec[l++];
    }
    cout<<ans<<endl;
}
相关推荐
锅包一切13 天前
PART2 双指针
c++·算法·leetcode·力扣·双指针
脏脏a16 天前
【优选算法・双指针】以 O (n) 复杂度重构数组操作:从暴力遍历到线性高效的范式跃迁
算法·leetcode·双指针·牛客·优选算法
识君啊16 天前
Java双指针 - 附LeetCode 经典题解
java·算法·leetcode·java基础·双指针
伟大的车尔尼16 天前
双指针题目:下一个排列
双指针
小冻梨66617 天前
ABC444 C - Atcoder Riko题解
c++·算法·双指针
伟大的车尔尼19 天前
双指针题目:压缩字符串
双指针
hnjzsyjyj23 天前
洛谷 P13270:【模板】最小表示法 ← 双指针 + 解环成链
字符串·双指针·解环成链
燃于AC之乐1 个月前
《算法实战笔记》第10期:六大算法实战——枚举、贪心、并查集、Kruskal、双指针、区间DP
算法·贪心算法·图论·双指针·区间dp·二进制枚举
睡不醒的kun1 个月前
不定长滑动窗口-求子数组个数
数据结构·c++·算法·leetcode·职场和发展·双指针·滑动窗口
伟大的车尔尼1 个月前
双指针题目:复写零
双指针