Solution
首先明确的是对每一次询问分开处理。
然后因为要求最大价值,可以想到用DP去做。设 (d_{i,j}) 表示前 (i) 个元素,以 (j) 颜色为结尾的最大价值。可以发现,每一个 (i) 最多只会更新一个 (dp) ,所以可以将第一维省略掉。
接下来我们思考第 (i) 个球会从哪些情况继承也就是状态转移:
1.这是子序列第 (1) 个球: (b imes v_i)
2.从上一个和它颜色相同的球的结尾的子序列转移: (dp_{c_i}+a imes v_i)
3.从和它颜色不一样的球的结尾的最大价值子序列转移: (maxlimits_{c_i ot=c_j}{dp_j}+b imes v_i)
但是因为3转移单次复杂度为 (O(n)) ,所以我们需要 (O(1)) 找到最优的那个 (j) 。
因为 (dp) 数组在转移后是单调不减的,所以可以保留最大值的颜色。
但是如果只保留转移前最大值的颜色,那么可能最大值的颜色和 (i) 一样,所以还要保留次大值的颜色,这样就能保证两个中起码有一个是3转移需要的。
然后更新最大值,次大值颜色, (dp_{c_i}) 的值和 (ans) 即可。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,INF=1e18;
int n,m,a,b,ans;
int v[N],c[N],dp[N];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
while(m--){
ans=0;
scanf("%lld%lld",&a,&b);
for(int i=1;i<=n;i++) dp[i]=-INF;
int t1=0,t2=0,tmp=0;
for(int i=1;i<=n;i++){
tmp=max(b*v[i],dp[c[i]]+a*v[i]);
if(c[i]!=t1) tmp=max(tmp,dp[t1]+b*v[i]);
else tmp=max(tmp,dp[t2]+b*v[i]);
if(tmp>dp[t1]){
if(t1!=c[i]){
t2=t1;
t1=c[i];
}
else t1=c[i];
}
else if(tmp>dp[t2]&&c[i]!=t1) t2=c[i];
dp[c[i]]=max(dp[c[i]],tmp);
ans=max(ans,tmp);
}
printf("%lld
",ans);
}
return 0;
}