[题解] CF549F Yura and Developers

洛谷传送门

Codeforces传送门

vjudge传送门

蒟蒻第一次写紫题题解,大佬轻喷。

题目大意:

给定一个数组 \(a\) 和常数 \(k\),求有多少个子区间满足区间和减去区间最大值是 \(k\) 的倍数。

思路:

考虑使用分治解决。

设区间 \([l,r]\) 最大值为 \(mx\)

对于 \(i(i\le mid)\)\(i\) 为左端点。

钦定 \(mx\) 在左边,这时只需要枚举右端点,满足 \(a_{mid+1\sim r}\) 这段区间的任何一个数不大于 \(mx\),不难发现可以使用双指针维护出满足上述条件的区间 \((mid,R]\)

\(sum\) 数组为前缀和数组。即:

\[sum_i = \begin{cases} sum_i=a_i & i=1\\ sum_i=sum_{i-1}+a_i & i>1 \end{cases} \]

\(r\in(mid,R]\),符合题目条件的个数。

则式子转化为 \(sum_r-sum_{i-1}-mx\equiv 0(mod\ k)\) 符合条件的个数,即 \(sum_r\in sum_{i-1}+mx(mod\ k)\)

而由于数据很小,\(k\) 只有 \(10^6\),不需要用到 \(map\),开一个桶维护上述式子就可以了。

\(mx\) 在左边的情况搞定了,在右边的情况同理。

复杂度为 \(O(n\log n)\)

代码:

AC记录

CP Editor 太好用啦

// Problem: CF549F Yura and Developers
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF549F
// Memory Limit: 250 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)


/*+ Nimbunny +*/

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pi pair<int, int>
// #pragma GCC optimize(2)

using namespace std;
const int INF = INT_MAX;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, m, a[3 * N], sum[3 * N], ans, b[N];

inline int read() {
    int x;
    cin >> x;
    return x;
}

void cdq(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    cdq(l, mid), cdq(mid + 1, r);
    int k = mid, ma = 0;
    for (int i = mid; i >= l; i--) {
        ma = max(ma, a[i]);
        while (k != r && a[k + 1] <= ma) {
            k++;
            b[sum[k] % m]++;
        }
        ans += b[(sum[i - 1] + ma) % m];
    }
    for (int i = mid + 1; i <= r; i++) b[sum[i] % m] = 0;
    k = mid + 1, ma = 0;
    for (int i = mid + 1; i <= r; i++) {
        ma = max(ma, a[i]);
        while (k != l && a[k - 1] < ma) {
            k--;
            b[sum[k - 1] % m]++;
        }
        ans += b[(sum[i] - ma) % m];
    }
    for (int i = l; i <= mid; i++) b[sum[i - 1] % m] = 0;
    return;
}

signed main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    n = read(), m = read();
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + (a[i] = read());
    cdq(1, n);
    cout << ans;
    return 0;
}
posted @ 2025-06-09 10:19  酱云兔  阅读(11)  评论(0)    收藏  举报