题解:AT_agc040_e [AGC040E] Prefix Suffix Addition
主观难度评价(参考
首先我们需要注意的是题目的条件自由度高,不易设置转移状态或证明一种贪心策略,此时通常的方法是用性质结论来人为限制/放宽条件,使得条件容易刻画。
具体到这个题,不同的区间可能是重叠的,这很不好刻画。因此我们希望区间尽可能不重叠,然后就能发现对于同一类的区间,确实是可以不重叠的。证明如下:
设我们选定
则容易设置
然而可能存在另一种方式,其序列数只比最优决策多一个,但是却拥有更优秀的决策。如
因此我们对每个
/* K_crane x N_cat */
#include <bits/stdc++.h>
#define lowbit(x) ((x) & (-(x)))
using namespace std;
const int N = 200010, INF = 1100000000;
int n, a[N];
struct node
{
int sum, u, d;
bool operator < (const node &w) const
{
if(sum != w.sum) return sum < w.sum;
else if(u != w.u) return u > w.u;
else return d < w.d;
}
bool operator > (const node &w) const
{
if(sum != w.sum) return sum > w.sum;
else if(u != w.u) return u < w.u;
else return d > w.d;
}
inline void debug() {cerr << "> " << sum << " " << u << " " << d << " ";}
}; node f[N][4][2];
inline void upd(int i, int j, node nd)
{
if(nd.sum < f[i][j][0].sum) f[i][j][1] = f[i][j][0], f[i][j][0] = nd;
else if(nd.sum == f[i][j][0].sum) f[i][j][0] = min(f[i][j][0], nd);
else if(nd.sum < f[i][j][1].sum) f[i][j][1] = nd;
else if(nd.sum == f[i][j][1].sum) f[i][j][1] = min(f[i][j][1], nd);
}
int main()
{
// freopen("text.in", "r", stdin);
// freopen("prog.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i];
for(int i = 0; i <= n; ++i)
for(int j = 0; j < 4; ++j)
for(int k = 0; k <= 1; ++k)
f[i][j][k] = {INF, a[i], 0};
f[0][0][0] = {0, 0, 0};
for(int i = 0; i < n; ++i)
{
for(int mask = 0; mask < 4; ++mask)
{
for(int ref = 0; ref < 4; ++ref)
{
for(int op = 0; op <= 1; ++op)
{
for(int to = 0; to < 4; ++to)
{
if(((mask | ref) & to) != to) continue;
int cost = f[i][mask][op].sum + __builtin_popcount(ref);
int U = ((ref & 2) ? INF : f[i][mask][op].u);
int D = ((ref & 1) ? 0 : f[i][mask][op].d);
if(to == 0)
{
if(a[i + 1] == 0)
upd(i + 1, 0, {cost, U, D});
}
else if(to == 1)
{
if(D <= a[i + 1])
upd(i + 1, 1, {cost, U, a[i + 1]});
}
else if(to == 2)
{
if(U >= a[i + 1])
upd(i + 1, 2, {cost, a[i + 1], D});
}
else if(to == 3)
{
if(U + D >= a[i + 1] && D <= a[i + 1])
upd(i + 1, 3, {cost, a[i + 1] - D, D});
if(U + D <= a[i + 1])
upd(i + 1, 3, {cost, U, a[i + 1] - U});
}
}
}
}
}
}
int ans = INF;
for(int i = 0; i < 4; ++i)
for(int j = 0; j <= 1; ++j)
ans = min(ans, f[n][i][j].sum);
cout << ans << '\n';
return 0;
}
/*
*/