扑克游戏
描述
有一种别样“小猫钓鱼”扑克游戏。有 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; }