Loading [MathJax]/extensions/tex2jax.js

Codeforces 933E:A Preponderant Reunion – 题解

主要思路

想了半天都不知道怎么刻画状态,后面发现可以转成一个泛化问题,就比较好理解了。

考虑不严格地减去最小值、而是任意值,并达到题目要求的结果。这个问题肯定不会更优,而最优解可以直接作为本题最优解。

如果是这样的话,那么我们可以试着先做一个区间 DP。设置 \(dp[l][r]\) 使得这一段区间全部清空、端点进行保留,那么构造出 \(c_l = p_l, c_i = \max(p_i – c_{i – 1}, 0)\),得到:

\[ \begin{aligned} f[l][r] &= \sum_{i = l}^{r – 2} c_i + c_{r – 1} + c_r \\ &= f[l][r – 2] + \max(p_r – c_{r – 1}, 0) + c_{r – 1} \\ &= f[l][r – 2] + \max(p_r, c_{r – 1}) \\ &\leq f[l][r – 2] + p_r \\ &= f[l][r – 2] + f[r][r] \end{aligned} \]

那么可以用这个直接做线性的 DP,讨论一下不同的长度,然后再反过去即可。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF933E.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 3e5 + 200;
typedef long long ll;
int n, ai[MAX_N], pi[MAX_N];
ll f[MAX_N];
bool opt[MAX_N];
vector<int> ans;
int process(int pos)
{
int val = min(ai[pos], ai[pos + 1]);
if (val)
ans.push_back(pos);
ai[pos] -= val, ai[pos + 1] -= val;
return val;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &ai[i]);
ll single = f[max(0, i - 2)] + ai[i], binary = f[max(0, i - 3)] + max(ai[i], ai[i - 1]);
f[i] = min(single, binary), opt[i] = f[i] != single;
}
int cnt = 0;
for (int i = min(f[n - 1], f[n]) == f[n - 1] ? n - 1 : n; i >= 1; i -= (opt[i] == true) + 2)
pi[++cnt] = i;
reverse(pi + 1, pi + 1 + cnt);
for (int i = 1; i <= cnt; i++)
{
int pre = pi[i - 1], curt = pi[i];
ll acc = 0;
if (opt[curt])
acc += process(curt - 1);
acc += process(pre + 1), acc += process(curt);
}
printf("%lld\n", 1LL * ans.size());
for (auto &x : ans)
printf("%d\n", x);
puts("");
return 0;
}
// CF933E.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 3e5 + 200; typedef long long ll; int n, ai[MAX_N], pi[MAX_N]; ll f[MAX_N]; bool opt[MAX_N]; vector<int> ans; int process(int pos) { int val = min(ai[pos], ai[pos + 1]); if (val) ans.push_back(pos); ai[pos] -= val, ai[pos + 1] -= val; return val; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &ai[i]); ll single = f[max(0, i - 2)] + ai[i], binary = f[max(0, i - 3)] + max(ai[i], ai[i - 1]); f[i] = min(single, binary), opt[i] = f[i] != single; } int cnt = 0; for (int i = min(f[n - 1], f[n]) == f[n - 1] ? n - 1 : n; i >= 1; i -= (opt[i] == true) + 2) pi[++cnt] = i; reverse(pi + 1, pi + 1 + cnt); for (int i = 1; i <= cnt; i++) { int pre = pi[i - 1], curt = pi[i]; ll acc = 0; if (opt[curt]) acc += process(curt - 1); acc += process(pre + 1), acc += process(curt); } printf("%lld\n", 1LL * ans.size()); for (auto &x : ans) printf("%d\n", x); puts(""); return 0; }
// CF933E.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 3e5 + 200;

typedef long long ll;

int n, ai[MAX_N], pi[MAX_N];
ll f[MAX_N];
bool opt[MAX_N];
vector<int> ans;

int process(int pos)
{
    int val = min(ai[pos], ai[pos + 1]);
    if (val)
        ans.push_back(pos);
    ai[pos] -= val, ai[pos + 1] -= val;
    return val;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &ai[i]);
        ll single = f[max(0, i - 2)] + ai[i], binary = f[max(0, i - 3)] + max(ai[i], ai[i - 1]);
        f[i] = min(single, binary), opt[i] = f[i] != single;
    }
    int cnt = 0;
    for (int i = min(f[n - 1], f[n]) == f[n - 1] ? n - 1 : n; i >= 1; i -= (opt[i] == true) + 2)
        pi[++cnt] = i;
    reverse(pi + 1, pi + 1 + cnt);
    for (int i = 1; i <= cnt; i++)
    {
        int pre = pi[i - 1], curt = pi[i];
        ll acc = 0;
        if (opt[curt])
            acc += process(curt - 1);
        acc += process(pre + 1), acc += process(curt);
    }
    printf("%lld\n", 1LL * ans.size());
    for (auto &x : ans)
        printf("%d\n", x);
    puts("");
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *