题意:有一排颜色的球,每次选择一个球消去,那么这个球所在的同颜色的整段都消去(和消消乐同理),若消去k个,那么得分k*k,问你消完所有球最大得分
思路:显然这里我们直接用二位数组设区间DP行不通,我们不能表示出“合并”这种情况。我们先把所有小块整理成连续的大块。
我们用click(l,r,len)表示消去l到r的所有大块和r后len块和r颜色一样的小块的最大得分。那么这样我们可以知道,click(l,r,len)只有两种情况:
1.r直接和后面len全都消去
2.r带着len先和前面的一样的颜色的一起消
代码:
#include<cmath> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 200 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; int num[maxn], a[maxn], p[maxn], cnt; int dp[maxn][maxn][maxn]; //j后还有k个一样的小块 int click(int l, int r, int len){ if(l > r) return 0; if(dp[l][r][len]) return dp[l][r][len]; if(l == r) return dp[l][r][len] = (num[l] + len) * (num[l] + len); dp[l][r][len] = click(l, r - 1, 0) + (num[r] + len) * (num[r] + len); for(int i = l; i < r; i++){ if(p[i] != p[r]) continue; dp[l][r][len] = max(dp[l][r][len], click(l, i, num[r] + len) + click(i + 1, r - 1, 0)); } return dp[l][r][len]; } int main(){ int t, ca = 1; scanf("%d", &t); while(t--){ int n; scanf("%d", &n); memset(num, 0, sizeof(num)); memset(dp, 0, sizeof(dp)); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); cnt = 0; a[0] = -INF; for(int i = 1; i <= n; i++){ if(a[i] != a[i - 1]){ ++cnt; num[cnt]++; p[cnt] = a[i]; } else{ num[cnt]++; } } printf("Case %d: %d\n", ca++, click(1, cnt, 0)); } return 0; }
原文地址:https://www.cnblogs.com/KirinSB/p/10645068.html
时间: 2024-10-16 19:59:17