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的数组

浙公网安备 33010602011771号