Atcoder ARC194A Operations on a Stack 题解 [ 黄 ] [ 观察 ] [ 线性 dp ]
Operations on a Stack:算是运用了一个常见观察 trick 的简单 dp 题。
观察
首先观察答案的形态,当我们使用一次删除栈顶操作时,同时也意味着不使用当前位的数字。
那我们连续使用两次删除操作呢?就意味着我们不使用当前位和当前位前面三位的数字了。但是继续观察,我们发现不使用这四位数字,即加加删删的操作,可以等效为加删加删的操作,这样也是相当于不使用这四位数字的。
因此所有连续的删除操作都可以等效为若干次加删操作,原题就被我们转化为了只能进行若干次单独的加删和加的操作了。这是观察的一个常见 trick,即对答案形态观察,将一部分限制或操作等效为另一种限制或操作,并且使答案不劣。
dp
于是可以设计 \(dp_{i,0/1}\) 表示考虑到第 \(i\) 位,不使用或者使用第 \(i\) 个数字的最大价值。使用这个数字时前一位用不用都可以,但是不使用时前一位就必须使用了,理由如上文所示。转移如下:
- \(dp_{i,0}\gets dp_{i-1,1}-a_{i-1}\)。
- \(dp_{i,1}\gets \max(dp_{i-1,0},dp_{i-1,1})+a_i\)。
时间复杂度 \(O(n)\),注意初始化 \(dp_{0,1}=-inf\),以保证第一位不会使用删除操作。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=200005;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n;
ll a[N],dp[N][2];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
dp[0][1]=-inf;
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i][1]=max(dp[i-1][0],dp[i-1][1])+a[i];
dp[i][0]=dp[i-1][1]-a[i-1];
}
cout<<max(dp[n][0],dp[n][1]);
return 0;
}

浙公网安备 33010602011771号