[CF549F] Yura and Developers

Yura and Developers の 传送门

点一点

题外话

怎么没人直接强上笛卡尔树分治。

正文

看到最大值,想一想笛卡尔树分治。

令当前区间为 \(\left [ l, r \right ]\),区间最大值及位置为 \(mx, k\)

假设 \(\left [ l, k \right ]\) 为短边(另一段为短边时也差不太多)。

满足条件的子段长成 \(sum_i-sum_{j-1}-mx \equiv 0 \left ( \bmod \ k \right )\)

移一移项,得 \(sum_i \equiv sum_{j-1}+mx \left ( \bmod \ k \right )\)

开个 map 把右边的 \(sum_i\) 存下来,暴力算左边每个数的贡献就行。

啸细节

存每个长边 \(sum_i\)map 可以直接一层层传下去,不要重新统计。

map 换成 __gnu_pbds::gp_hash_table(详见这里)。

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define int long long
using namespace std;
inline int read()
{
    int f = 0, ans = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        ans = (ans << 3) + (ans << 1) + c - 48, c = getchar();
    return f ? -ans : ans;
}
void write(int x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
const int N = 3e5 + 5;
int n, _K, a[N];
int ans, s[N];
__gnu_pbds::gp_hash_table<int, int> mp;
template <typename T>
inline T Mod(T &&x) { return x >= _K ? x -= _K : x; }
namespace ST
{
    pair<int, int> f[19][N];
    inline void init()
    {
        for (int i = 1; i <= n; ++i)
            f[0][i] = {a[i], i};
        for (int j = 1; j <= __lg(n); ++j)
            for (int i = 1; i + (1 << j) - 1 <= n; ++i)
                f[j][i] = max(f[j - 1][i], f[j - 1][i + (1 << j - 1)]);
    }
    inline pair<int, int> get_max(int l, int r)
    {
        int lg = __lg(r - l + 1);
        return max(f[lg][l], f[lg][r - (1 << lg) + 1]);
    }
}
void solve(int l, int r, int d)
{
    if (l >= r)
    {
        ans += l == r;
        return;
    }
    auto [mx, k] = ST::get_max(l, r);
    mx %= _K;
    if (k - l <= r - k)
    {
        for (int i = l; i < k; ++i)
            --mp[s[i]];
        for (int i = l; i <= k; ++i)
            ans += mp[Mod(s[i - 1] + mx)];
        --mp[s[k]];
        solve(k + 1, r, d + 1);
        mp.clear();
        for (int i = l; i < k; ++i)
            ++mp[s[i]];
        solve(l, k - 1, d + 1);
    }
    else
    {
        for (int i = k + 1; i <= r; ++i)
            --mp[s[i]];
        ++mp[s[l - 1]], --mp[s[k]];
        for (int i = k; i <= r; ++i)
            ans += mp[Mod(s[i] - mx + _K)];
        --mp[s[l - 1]];
        solve(l, k - 1, d + 1);
        mp.clear();
        for (int i = k + 1; i <= r; ++i)
            ++mp[s[i]];
        solve(k + 1, r, d + 1);
    }
}
signed main()
{
    // freopen(".in", "r", stdin);
    // freopen(".out", "w", stdout);
    n = read(), _K = read();
    for (int i = 1; i <= n; ++i)
    {
        Mod(s[i] = s[i - 1] + (a[i] = read()) % _K);
        ++mp[s[i]];
    }
    ST::init();
    solve(1, n, 0);
    write(ans - n);
    return 0;
}
posted @ 2025-01-24 18:13  SilverLi  阅读(40)  评论(6)    收藏  举报