DP这东西还是一如既往的毁天灭地的难啊。
题意:有n个人参加非诚勿扰,每个人都有 ni n i 的屌丝值,如果前面有k个人比他早,他就会有 (k−1)∗(ni) ( k − 1 ) ∗ ( n i ) 的屌丝值,你可以让一些人进入一个小黑屋,来改变上场顺序,但是小黑屋是类似栈,先入后出。
题解:
dp[i][j]表示i~j区间的最优解。
对于i~j区间来说,第i个人可以第一个上,也可以最后一个(第j-i+1个)上,然后就需要枚举第i个人到底第几个上。
dp[i][j] = min(dp[i][j],dp[i + 1][i + k - 1] +num[i] * (k - 1) + dp[i + k][j] + k*(sum[j] - sum[i + k - 1]));
假设第i个人第k个上,那么就要增加(k-1)*num[i]的屌丝值,然后i+k~j的人之前有k个人,所以各自要增加k倍的屌丝值。
(之前我想的是在区间[i,j]枚举第k个人,然后在这个区间里最后一个上场,错的离谱。)
(总有一种自己DP越来越好一点的错觉。。。。但是还是一道题都想出不出来。好菜啊。。。。。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f;
int n,num[105],dp[105][105],sum[105];
int main()
{
int T,testCase = 1;;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
memset(dp,0,sizeof dp);
for (int i = 1; i <= n; i++)
{
scanf("%d",&num[i]);
}
sum[0] = 0;
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + num[i];
}
for (int i = 1;i <= n;i++)
{
for (int j = i + 1; j <= n; j++)
dp[i][j] = INF;
}
for (int i = n; i >= 1; i--)
{
for (int j = i + 1; j <= n; j++)
{
for (int k = 1; k <= j - i + 1; k++)
{
dp[i][j] = min(dp[i][j],dp[i + 1][i + k - 1] +num[i] * (k - 1) + dp[i + k][j] + k*(sum[j] - sum[i + k - 1]));
}
}
}
printf("Case #%d: %d\n",testCase++,dp[1][n]);
}
}