题目分析
现场赛看了这道题并没有写,是因为队友说的题意我理解多了,本来是一个buff三回合之后就没有了,但是我认为只要加上了一个buff那么久一直有这个buff,想dp方程的时候发现有后效性,然后就写不出来了。回来之后重新读题发现一个buff三回合之后消失,那么很明显我们就可以只需知道这回合,上回合以及上上回合选什么buff,然后就可以直接写状态转移方程了,时间复杂度 O(n∗33) 。这里我的dp[i][j][k]表示到底i个回合,这个回合选第j个buff,上个回合选第k个buff。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e4+100;
double a[maxn][4], dp[maxn][4][4];
double solve(int id, int _a, int _b, int _c){
double tot[4];
tot[1] = tot[2] = tot[3] = 1.0;
tot[_a] += a[id][_a];
tot[_b] += a[id-1][_b];
tot[_c] += a[id-2][_c];
return tot[1]*tot[2]*tot[3];
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= 3; j++)
scanf("%lf", &a[i][j]);
for(int i = 1; i <= 3; i++)
for(int j = 1; j <= 3; j++)
if(i == j) dp[2][i][j] = (1.0+a[1][j])+(1.0+a[1][j]+a[2][i]);
else dp[2][i][j] = (1.0+a[1][j]) + (1.0+a[1][j])*(1.0+a[2][i]);
for(int i = 3; i <= n; i++){
for(int aa = 1; aa <= 3; aa++){
for(int bb = 1; bb <= 3; bb++){
for(int cc = 1; cc <= 3; cc++){
dp[i][aa][bb] = max(dp[i][aa][bb], dp[i-1][bb][cc] + solve(i, aa, bb, cc));
}
}
}
}
double ans = 0;
for(int i = 1; i <= 3; i++)
for(int j = 1; j <= 3; j++)
ans = max(ans, dp[n][i][j]);
printf("%.6lf\n", ans);
}
return 0;
}