atcoder 440 C

原题

(https://atcoder.jp/contests/abc440/tasks/abc440_c)
题目大意分析就是:你会获得一个大小为n的数组,以及一个w,你可以随机选择一个正整数x,然后(i+x)%2*w的结果如果<w,那么就把这个下标为i的数字涂成黑色
每个格子涂成黑色都有一个代价,要求这个代价的最小值

分析

所有i+x对2w取模之后小于w的i的代价都会被加起来
假设有一个周长为2w的圆,
假设w等于2
假设原来的下标是1 2 3 4 5 6
当x=0时,那么就是i%4时,余数为0和1的被选取 0 1 2 3 是 是 否 否
当x=1时,那么就是i%4时,余数为3和0的被取走 0 1 2 3 是 否 否 是
当x=2时,那么就是i%4时,余数为2和3的被取走 0 1 2 3 否 否 是 是
这个x在这里的作用 其实就是在2w周长的这个圆上,取一段连续的x长度的和,再给它加起来

然后就可以用到滑动窗口的知识了

在这里我们还可以看到的就是,这个S数组开始的时候是初始化为0的,这个也挺重要的
因为我们是在这个周长为2w的数组上选一段连续的长度为w的一段,这一段中可能是没有的,也就是说,这一段中可能选到了x,但是原来的数字中没有数字%2w之后余x的,这个时候就是加上0的代价
(感觉这个没必要说哎。。。。

AC代码

#include<bits/stdc++.h>
using namespace std;
//"O campeão tem nome, e se chama Charles Oliveira!"
#define int long long
#define endl '\n'
#define ep emplace
#define pob 
#define ll long long
#define pb push_back
#define pof pop_front
#define pob pop_back
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define mod 998244353
#define MOD 1000000007
const int N=200005;

using ld = long double;
using ui = unsigned;
using ull = unsigned long long;
using i128 = __int128;


//所有i+x对2w取模之后小于w的i的代价都会被加起来
//假设有一个周长为2w的圆,
//假设w等于2
//假设原来的下标是1 2 3 4 5 6 
//当x=0时,那么就是i%4时,余数为0和1的被选取  0 1 2 3 是 是 否 否
//当x=1时,那么就是i%4时,余数为3和0的被取走  0 1 2 3 是 否 否 是
//当x=2时,那么就是i%4时,余数为2和3的被取走  0 1 2 3 否 否 是 是
//这个x在这里的作用 其实就是在2w周长的这个圆上,取一段连续的x长度的和,再给它加起来
void solve() {
    int N, W;
    cin>>N>>W;
    // 周期为 2W,统计每个余数对应的总成本
    int period = 2 * W;
    vector<long long> S(period, 0);
    for (int i = 1; i <= N; ++i) {
        long long cost;
        cin >> cost; 
        // i % period 得到该位置在周期内的偏移量
        S[i % period] += cost;
    }
    // 寻找环形数组中长度为 W 的连续子段最小和
    // 使用滑动窗口。为了处理环形,我们可以将数组逻辑上扩展(或者用取模)
    long long current_window_sum = 0;
    
    // 初始窗口 [0, W-1]
    for (int i = 0; i < W; ++i) {
        current_window_sum += S[i];
    }

    long long min_cost = current_window_sum;

    // 滑动窗口遍历所有可能的起点
    for (int i = 0; i < period; ++i) {
        // 窗口移动:减去旧的起点 S[i],加上新的终点 S[(i + W) % period]
        current_window_sum -= S[i];
        current_window_sum += S[(i + W) % period];
        min_cost = min(min_cost, current_window_sum);
    }

    cout << min_cost << "\n";
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t=1;
    cin>>t;
    while(t--)solve();
}

current_window_sum += S[(i + W) % period];不断维护一个长度为w的数组

posted @ 2026-03-26 11:05  Time_q  阅读(5)  评论(0)    收藏  举报