描述
有一种别样“小猫钓鱼”扑克游戏。有 N 张牌,每张牌都有一个花色和点数。游戏 的规则:扑克接龙时,若前面有同样花色的牌,你可以将这两张牌连同之间的牌都取走, 得到的分值为取走牌点数之和。这里说的是可以,不是必须。给定扑克接龙的顺序,求 最多的得分。
输入
第一行一个整数 N。
第二行 N 个整数,依次表示 1~N 张牌的花色。
第三行 N 个整数,依次表示 1~N 张牌的点数。
输出
一个整数,为游戏可以得到最大得分。
输入样例 1
7
1 2 1 2 3 2 3
1 4 3 4 3 4 5
输出样例 1
23
提示
数据范围:1<=n<=3000
题目来源
思路
强行枚举肯定超时,这个就不多说了......
设dp[i]为前i张牌可以取到的的最大得分,最终只需要输出dp[n]即可;
dp[i]的值应该怎么取?
首先要考虑一种特殊情况:第i张牌的花色a[i]有可能是第一次出现的,也就是前面没有与它相同花色的牌,所以可以先让dp[i]=dp[i-1]。
接下来怎么做?重点来了!
由题意得,dp[i]=dp[j-1]+(b[j]+b[j+1]+...+b[i])(1<=j<i),其中对j能取到的每一个值代入,再确定dp[i]能取到的最大值即可。
这里有一个小细节:
b[j]+b[j+1]+...+b[i]的值如果直接求和,(有可能不)会出现超时的情况,所以我们可以再输入的时候进行一个求前缀和的操作,最后计算b[i]-b[j-1]的值就可以了
代码:
#include<iostream>
using namespace std;
int n,a[3005],b[3005],dp[3005],ans;
int main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
cin>>b[i];
dp[i]=b[i];
b[i]+=b[i-1];
}
for(int i=1;i<=n;i++){
dp[i]=dp[i-1];
for(int j=1;j<i;j++)
if(a[j]==a[i])
dp[i]=max(dp[i],dp[j-1]+b[i]-b[j-1]);
}
cout<<dp[n];
return 0;
}