Codeforces 264C Choosing Balls 动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/CF264C.html
题目传送门 - CF264C
题意
给定一个有 $n$ 个元素的序列,序列的每一个元素是个球,第 $i$ 个球具有 $v_i$ 的值,颜色为 $c_i$ 。
一个序列的价值为每一个球价值和。
在一个序列中,第 $i$ 个球的价值为:
当 $c_i=c_{i-1}(i>1)$ 时,$value=a\times v_i$。
否则, $value=b\times v_i$ 。
接下来有 $q$ 组询问,每组询问给定 $a,b$ ,问在当前给定的 $a,b$ 下,原序列所有子序列(不一定要连续)的价值中的最大值。
$n\leq 10^5,q\leq 500$
题解
我们对于每一次询问分别处理。
首先我们考虑动态规划。
用 $dp[i][j]$ 表示前 $i$ 个元素中子序列以 颜色 $j$ 结尾的最大价值。
首先我们考虑每一个 $i$ 所代表的新球只会更新一个 $dp[i][j]$ ,所以我们可以把 $i$ 这一维省掉。
接下来我们考虑第 $i$ 个球的结果可能会从哪些情况继承:
1. 当前球为子序列第一个: $b\times v_i$
2. 从上一个和他颜色相同的球结尾的子序列继承:$dp[c_i]+a\times v_i$
3. 从和他颜色不同的球结尾的最大价值子序列继承:$dp[x]+b\times v_i$
现在最棘手的是如何找第 $3$ 种情况中的 $x$ 。
做法是:我们记录当前情况下 $dp$ 值最大和次大的颜色。
这两个中一定有一个是第三种情况需要的,所以就可以完成第三种情况了。
最后然后再拿当前球的结果更新 DP 数组的相应值即可。
代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N=100005; const LL INF=1LL<<56; LL read(){ int x; scanf("%d",&x); return 1LL*x; } int n,q,c[N]; LL v[N],dp[N]; int main(){ scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) v[i]=read(); for (int i=1;i<=n;i++) scanf("%d",&c[i]); while (q--){ LL a=read(),b=read(); LL ans=0; int Max=0,Nxt=0; for (int i=0;i<=n;i++) dp[i]=-INF; for (int i=1;i<=n;i++){ int color=c[i]; LL now=max(dp[color]+a*v[i],b*v[i]); if (color!=Max) now=max(now,dp[Max]+b*v[i]); else/* if (color!=Nxt)*/ now=max(now,dp[Nxt]+b*v[i]); if (now>dp[Max]){ if (Max!=color) Nxt=Max,Max=color; } else if (now>dp[Nxt]&&color!=Max) Nxt=color; dp[color]=max(dp[color],now); ans=max(ans,now); } printf("%I64d\n",ans); } return 0; }