板刷2023

CF1822 G1. Magic Triples (Easy Version)

image-20231007141029950

1ai106

题解

  • 显然关键在于j,我们不妨枚举j,显然a[i]a[j]的约数
  • 对于每个a[j]来说,枚举其约数,然后即可求出倍数b,那么可得到ak
  • 时间复杂度:O(1000n)
int n, a[N];
map<int, int> mp;

void solve()
{
    mp.clear();
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        mp[a[i]]++;
    }
    int ans = 0;
    for (auto [x, y] : mp)
    {
        // cerr << x << " " << y << endl;
        vector<int> div;
        for (int i = 1; i <= x / i; ++i)
        {
            if (x % i == 0)
            {
                div.push_back(i);
                if (i != x / i)
                    div.push_back(x / i);
            }
        }
        for (auto val : div)
        {
            // cerr << val << ", ";
            int t = x / val;
            if (mp.count(val) && mp.count(x * t))
            {
                if (x == val && y >= 3)
                    ans += y * (y - 1) * (y - 2);
                else if (x != val)
                    ans += y * mp[val] * mp[x * t];
                // cerr << val << " " << x << " " << x * t << endl;
                // cerr << "x = " << x << ", ans = " << ans << endl;
            }
        }
    }
    cout << ans << endl;
}

CF1801 B. Buying gifts

image-20231007141524114

题解

  • 我们不妨枚举每个a[i]作为第一个人的最大值,所以对a[i]降序排列
  • 对于某个a[i]来说,一旦我们将其作为第一个人的最大值,那么对于每个j,j>i,礼物一定是卖给第二个人的,所以我们在[i+1,n]中找到b[j]的最大值,ST表查询即可,我们设最大值为mx
  • 如果mxa[i],那么答案一定为mxa[i]
  • 如果mx<a[i],我们检查一下b[1,i1]中有没有更接近a[i]的值,可以用set维护前缀实现,然后二分即可
int n, st[N][22], lg2[N];
array<int, 2> c[N];

void build()
{
    for (int i = 1; i <= n; ++i)
        st[i][0] = c[i][1];
    for (int i = 2; i <= n; ++i)
        lg2[i] = lg2[i >> 1] + 1;
    for (int j = 1; j <= 20; ++j)
        for (int i = 1; i + (1ll << j) - 1 <= n; ++i)
            st[i][j] = max(st[i][j - 1], st[i + (1ll << (j - 1))][j - 1]);
}
int query(int l, int r)
{
    int len = lg2[r - l + 1];
    return max(st[l][len], st[r - (1ll << len) + 1][len]);
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> c[i][0] >> c[i][1];
    sort(c + 1, c + n + 1);
    build();
    multiset<int> st;
    int ans = INF;
    for (int i = 1; i <= n; ++i)
    {
        int a = c[i][0], b = c[i][1];
        if (i < n)
        {
            int mx = query(i + 1, n);
            if (mx >= a)
                ans = min(ans, abs(mx - a));
            else
            {
                ans = min(ans, abs(mx - a));
                auto l = st.upper_bound(a);
                auto r = st.lower_bound(a);
                if (st.size())
                {
                    l = prev(l);
                    ans = min(ans, abs(*l - a));
                }
                if (r != st.end())
                    ans = min(ans, abs(*r - a));
            }
        }
        else
        {
            auto l = st.upper_bound(a);
            auto r = st.lower_bound(a);
            if (st.size())
            {
                l = prev(l);
                ans = min(ans, abs(*l - a));
            }
            if (r != st.end())
                ans = min(ans, abs(*r - a));
        }
        st.insert(b);
    }
    cout << ans << endl;
}

CF1797 D. Li Hua and Tree

image-20231007142503977

题解

  • 维护每个节点的重儿子和所有儿子子树的点权和,所有儿子子树的点数和,每个节点的父节点
  • 考虑每个节点维护setset中存放一个pair(sz[u],u):uu
  • 每次操作二,我们不仅需要更新xsonx的信息,同时需要更新fax的信息,因为有可能fax的重儿子会改变,然后再更新3个节点之间的父子关系
  • 细节比较多,但是思路出的很快,本题难点在于对于操作2时更新信息时考虑需要更加全面
int n, q, a[N], hson[N], sz[N], sum[N], fa[N];
vector<int> g[N];
multiset<array<int, 2>> st[N];

void dfs(int u, int par)
{
    sz[u] = 1;
    sum[u] = a[u];
    hson[u] = -1;
    fa[u] = par;
    for (auto v : g[u])
    {
        if (v == par)
            continue;
        dfs(v, u);
        if (hson[u] == -1 || sz[hson[u]] < sz[v])
            hson[u] = v;
        else if (hson[u] != -1 && sz[hson[u]] == sz[v])
        {
            if (v < hson[u])
                hson[u] = v;
        }
        st[u].insert({sz[v], -v});
        sz[u] += sz[v];
        sum[u] += sum[v];
    }
}

void solve()
{
    cin >> n >> q;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1, u, v; i < n; ++i)
    {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    while (q--)
    {
        int op, u;
        cin >> op >> u;
        if (op == 1)
            cout << sum[u] << endl;
        else
        {
            if (hson[u] == -1)
                continue;
            int v = hson[u];
            st[u].erase(st[u].find({sz[v], -v}));
            st[fa[u]].erase(st[fa[u]].find({sz[u], -u}));
            sum[u] -= sum[v];
            sz[u] -= sz[v];
            if (st[u].size())
                hson[u] = -(*prev(st[u].end()))[1];
            else
                hson[u] = -1;

            sz[v] += sz[u];
            sum[v] += sum[u];
            st[v].insert({sz[u], -u});
            st[fa[u]].insert({sz[v], -v});
            if (st[v].size())
                hson[v] = -(*prev(st[v].end()))[1];
            else
                hson[v] = -1;

            if (st[fa[u]].size())
                hson[fa[u]] = -(*prev(st[fa[u]].end()))[1];
            else
                hson[fa[u]] = -1;

            fa[v] = fa[u], fa[u] = v;
        }
    }
}

CF1796 D. Maximum Subarray

image-20231007143237032

题解

  • 显然最大子段和问题可以通过线段树来解决
  • 我们贪心的考虑,如果x>0,那么我们一定是给一段连续的位置$ + x-x+x$,那么每次枚举只需要单点修改两个位置即可
  • 对于x<0的情况,和上面的情况反过来后滑动窗口枚举即可
int n, k, x, a[N];

struct info
{
    int ans, pre, suf, sum;
    info(int a = 0, int b = 0, int c = 0, int d = 0) : ans(a), pre(b), suf(c), sum(d) {}
    friend info operator+(const info &a, const info &b)
    {
        info c;
        c.ans = max({a.ans, b.ans, a.suf + b.pre});
        c.pre = max(a.pre, a.sum + b.pre);
        c.suf = max(b.suf, a.suf + b.sum);
        c.sum = a.sum + b.sum;
        return c;
    }
};
struct SEG
{
    info val;
} seg[N << 2];

void up(int id) { seg[id].val = seg[lson].val + seg[rson].val; }
void build(int id, int l, int r)
{
    if (l == r)
    {
        seg[id].val = info(a[l], a[l], a[l], a[l]);
        return;
    }
    int mid = l + r >> 1;
    build(lson, l, mid);
    build(rson, mid + 1, r);
    up(id);
}
void change(int id, int l, int r, int x, int val)
{
    if (l == r)
    {
        seg[id].val.ans += val;
        seg[id].val.pre += val;
        seg[id].val.suf += val;
        seg[id].val.sum += val;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        change(lson, l, mid, x, val);
    else
        change(rson, mid + 1, r, x, val);
    up(id);
}

void solve()
{
    cin >> n >> k >> x;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    build(1, 1, n);
    if (x == 0)
    {
        cout << max(0ll, seg[1].val.ans) << endl;
        return;
    }
    if (x > 0)
    {
        for (int i = 1; i <= k; ++i)
            change(1, 1, n, i, x);
        for (int i = k + 1; i <= n; ++i)
            change(1, 1, n, i, -x);
        int ans = seg[1].val.ans;
        for (int i = k + 1; i <= n; ++i)
        {
            change(1, 1, n, i - k, -2 * x);
            change(1, 1, n, i, 2 * x);
            ans = max(ans, seg[1].val.ans);
        }
        cout << max(0ll, ans) << endl;
    }
    else
    {
        x = -x;
        for (int i = 1; i <= n - k; ++i)
            change(1, 1, n, i, x);
        for (int i = n - k + 1; i <= n; ++i)
            change(1, 1, n, i, -x);
        int ans = seg[1].val.ans;
        for (int i = n - k + 1; i <= n; ++i)
        {
            change(1, 1, n, i - n + k, -2 * x);
            change(1, 1, n, i, 2 * x);
            ans = max(ans, seg[1].val.ans);
        }
        cout << max(0ll, ans) << endl;
    }
}

CF1779 D. Boris and His Amazing Haircut

image-20231007143817629

题解

  • 显然贪心的考虑,我们会从大到小的进行取min
  • 一个显然的结论:如果存在b[i]>a[i],那么a一定不可能变成b
  • 所以我们不妨将每个b[i]离散化后,对每个b[i]开个Vector,里面存放所有b[i]<a[i]的位置
  • 对于任意两个位置i,j来说,如果[i,j]之间出现x>b[i],那么修改次数一定会 +1,所以利用st表查询最大值即可
  • 然后对于每个b[i],检查修改次数是否小于给定的修改次数即可
int n, q, a[N], b[N], st[N][22], lg2[N];
map<int, int> mp;
vector<int> vec[N];

void build()
{
    for (int i = 1; i <= n; ++i)
        st[i][0] = b[i];
    for (int i = 2; i <= n; ++i)
        lg2[i] = lg2[i >> 1] + 1;
    for (int j = 1; j <= 20; ++j)
        for (int i = 1; i + (1ll << j) - 1 <= n; ++i)
            st[i][j] = max(st[i][j - 1], st[i + (1ll << (j - 1))][j - 1]);
}
int query(int l, int r)
{
    int len = lg2[r - l + 1];
    return max(st[l][len], st[r - (1ll << len) + 1][len]);
}

void solve()
{
    mp.clear();
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    vector<int> nums;
    bool ok = true;
    for (int i = 1; i <= n; ++i)
    {
        cin >> b[i];
        if (b[i] > a[i])
            ok = false;
        nums.push_back(b[i]);
    }
    cin >> q;
    for (int i = 1; i <= q; ++i)
    {
        int x;
        cin >> x;
        mp[x]++;
    }
    if (!ok)
    {
        cout << "NO" << endl;
        return;
    }
    sort(all(nums));
    nums.erase(unique(all(nums)), nums.end());
    for (int i = 1; i <= n; ++i)
        b[i] = lower_bound(all(nums), b[i]) - nums.begin() + 1;
    build();
    int m = (int)nums.size();
    for (int i = 1; i <= m; ++i)
        vec[i].clear();
    for (int i = 1; i <= n; ++i)
    {
        if (a[i] > nums[b[i] - 1])
            vec[b[i]].push_back(i);
    }
    for (int i = 1; i <= m; ++i)
    {
        // cerr << i << endl;
        if (vec[i].empty())
            continue;
        int cnt = 0;
        for (int j = 0; j < (int)vec[i].size() - 1; ++j)
        {
            int l = vec[i][j], r = vec[i][j + 1];
            // cerr << l << " " << r << " " << nums[i - 1] << endl;
            if (query(l, r) > i)
                cnt++;
        }
        cnt++;
        if (!mp.count(nums[i - 1]) || mp[nums[i - 1]] < cnt)
        {
            cout << "NO" << endl;
            // cerr << "cnt = " << cnt << endl;
            return;
        }
    }
    cout << "YES" << endl;
}

CF1748 C. Zero-Sum Prefixes

image-20231007144539848

题解

  • 我们定义pre[i]=a[1]+a[2]+...+a[i]
  • 显然对于i,j,i<j,a[i]=0,a[j]=0来说,我们在a[i]位置上+xpre[i]的影响,可以在a[j]x抵消掉,所以我们贪心的考虑每一段由0分开的区间之间,出现次数最多的pre[i]就是我们可以使其变为0的前缀,利用map记录次数即可
int n, a[N], pre[N];

void solve()
{
    cin >> n;
    a[n + 1] = 0;
    vector<int> vec;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
        if (a[i] == 0)
            vec.push_back(i);
    }
    vec.push_back(n + 1);
    for (int i = 1; i <= n; ++i)
        pre[i] = pre[i - 1] + a[i];
    int ans = 0;
    for (int i = 1; i < vec.front(); ++i)
        if (pre[i] == 0)
            ans++;
    for (int i = 0; i < (int)vec.size() - 1; ++i)
    {
        int l = vec[i], r = vec[i + 1];
        map<int, int> mp;
        int mx = 0;
        for (int j = l; j < r; ++j)
        {
            mp[pre[j]]++;
            mx = max(mx, mp[pre[j]]);
        }
        // cerr << l << " " << r << endl;
        ans += mx;
    }
    cout << ans << endl;
}
posted @   Zeoy_kkk  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示