题解:P16647 [GKS 2018 #D] Candies

题目传送门

题目大意

给定一个数组 \(S\) 长度为 \(n\),在其中选取一段连续区间,且需满足:

  • 区间内甜度为奇数的糖果数量 \(\le O\)
  • 区间总甜度 \(\le D\)

在保证以上要求的情况下使区间内甜度的和最大化。

sol

优先可以想到滑动窗口维护区间和最大,可是甜度可以为负数,所以可以在维护滑动窗口的双指针写法中加入前缀和与二分来实现。

具体实现见代码注释:

:::info[code]{open}

#include<bits/stdc++.h>
using namespace std;
const long long INF = 1e18;
int T;
int main() {
    cin >> T;
    for (int t = 1; t <= T; t++) {
        cout << "Case #" << t << ": ";
        int n, o;
        long long d;
        cin >> n >> o >> d;
        vector<long long> x(n + 2);
        long long A, B, C, M, L;
        cin >> x[1] >> x[2] >> A >> B >> C >> M >> L;
        vector<long long> s(n + 1);
        // qzh1[i]:前i颗糖果中奇数甜度的数量
        vector<int> qzh1(n + 1);
        // qzh2[i]:前i颗糖果的总甜度
        vector<long long> qzh2(n + 1);
        for (int i = 3; i <= n; i++) {
            x[i] = (A * x[i - 1] + B * x[i - 2] + C) % M;
        }
        for (int i = 1; i <= n; i++) {
            s[i] = x[i] + L;
            // 奇数糖果数量前缀和:s[i]是奇数就+1,否则+0
            qzh1[i] = qzh1[i - 1] + (s[i] % 2 != 0);
            // 总甜度前缀和
            qzh2[i] = qzh2[i - 1] + s[i];
        }
        long long ans = -INF;
        // set存储(前缀和值,下标),自动按前缀和升序排序
        set<pair<long long, int>> st;
        // 先插入前缀和0(对应前0颗糖果),这是滑动窗口的起点
        st.insert({qzh2[0], 0});
        
        // 滑动窗口左边界,初始在0位置
        int l = 0;
        // 枚举滑动窗口右边界 r(表示以r结尾的连续子数组)
        for (int r = 1; r <= n; r++) {
            // 约束1:窗口内奇数糖果数量不能超过 o
            // 如果当前窗口 [l+1, r] 奇数数量超标,就移动左边界并删除对应前缀和
            while (qzh1[r] - qzh1[l] > o) {
                st.erase({qzh2[l], l});
                l++;
            }
            // 约束2:总甜度 <= d
            // 即 qzh2[r] - qzh2[k] <= d  →  qzh2[k] >= qzh2[r] - d
            // 在set中找第一个 >= (qzh2[r]-d) 的前缀和
            auto it = st.lower_bound({qzh2[r] - d, -1});
            // 如果找到了合法的k,就更新最大甜度
            if (it != st.end()) {
                ans = max(ans, qzh2[r] - it->first);
            }
            // 把当前右端点的前缀和加入set,供后续使用
            st.insert({qzh2[r], r});
        }
        
        // 如果还是负无穷,说明没有合法方案
        if (ans == -INF) {
            cout << "IMPOSSIBLE\n";
        } else {
            cout << ans << "\n";
        }
    }
    return 0;
}

:::

posted @ 2026-06-13 12:36  Synthx  阅读(4)  评论(0)    收藏  举报