首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

HDU Non 循環移位前綴和非負:單調隊列優化 O(n) 解法

     編輯:關於C++

問題描述

長度 n(≤10⁶)序列,循環左移 k 位(0≤k

核心轉化

序列複製一遍拼接成長度 2n。原問題等價於:在長度 2n 的前綴和數組 sum[i] 中,找長度為 n 的滑動窗口,使得窗口內最小值 ≥ 窗口起始位置前的值(即 min_{i∈[k+1,k+n]} sum[i] ≥ sum[k])。

單調隊列維護滑動窗口最小值

  • 隊列存下標,單調遞增(隊首最小)
  • 入隊:彈出隊尾所有 ≥ 當前值的下標
  • 出隊:隊首下標 < 窗口左邊界則彈出

完整代碼

#include 
using namespace std;
const int MAXN = 2000005;

int n, a[MAXN];
long long sum[MAXN];
int q[MAXN], head, tail;

void push(int i) {
    while (head < tail && sum[i] <= sum[q[tail-1]]) --tail;
    q[tail++] = i;
}

void pop(int i, int window_len) {
    if (q[head] <= i - window_len) ++head;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while (cin >> n, n) {
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
            sum[i] = sum[i-1] + a[i];
        }
        for (int i = n+1; i <= 2*n; ++i)
            sum[i] = sum[i-1] + a[i-n];
        
        head = tail = 0;
        int ans = 0;
        // 初始化前 n-1 個元素進隊
        for (int i = 1; i < n; ++i) push(i);
        
        // 滑動窗口 [i-n+1, i] 對應移位 k = i-n
        for (int i = n; i <= 2*n; ++i) {
            push(i);
            pop(i, n);
            if (sum[q[head]] >= sum[i-n]) ++ans;
        }
        cout << ans << '\n';
    }
    return 0;
}

關鍵點解析

步驟說明
拼接數組a[n+1..2n] = a[1..n],前綴和同理延伸
窗口對應窗口 [k+1, k+n] 對應移位 k,條件 min(sum) ≥ sum[k]
隊列初始化先放入前 n-1 個,第 n 個開始完整窗口
出隊條件下標 ≤ i-n 視為超出窗口左邊界

複雜度

  • 時間:O(n) 每測試用例,每個元素進出隊各一次
  • 空間:O(n) 存前綴和與隊列

避坑指南

  • n=1 時特殊處理:單元素 ≥0 則 ans=1 否則 0
  • 前綴和用 long long(n×1000 ≤ 10⁹,但累加 2n 可能更大)
  • 輸入以 0 結束,while(cin>>n, n)
  • 隊列下標從 1 開始與前綴和對齊
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved