HDU4283 You Are the One(区间dp)
题意:
有n个选手,每个人都有一个愤怒值a[i],当第i位选手是第k个出场的时候,他的愤怒值为(k-1)*a[i];
有一个黑箱子(堆栈),可以往里面放人(改变出场次序),问最小的愤怒值。
解析:
dp[i][j]保存的是i到j之间最大的愤怒值减小量。
假设第i个人第k个上场,那么后面第i+1到第K个人就会都提前一名上场,第K个人到第J个人愤怒值不变。
也就是dp[i][j]=min(a[i]*(k-1)+sum[i]-sum[k]+dp[i+1][k]+dp[k+1][j]);
最后输出原始值+减小量即可
附上ac代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; #define N 105 int a[N],sum[N],dp[N][N]; int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); for(int y=1;y<=t;y++) { int n,ans=0; scanf("%d",&n); sum[0]=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; ans=ans+a[i]*(i-1); } memset(dp,0,sizeof(dp)); for(int i=1;i<n;i++) dp[i][i+1]=min(dp[i][i+1],a[i]-a[i+1]); for(int l=2;l<n;l++) { for(int i=1;i+l<=n;i++) { int j=i+l; for(int k=i;k<=j;k++) dp[i][j]=min(dp[i][j],a[i]*(k-i)-sum[k]+sum[i]+dp[i+1][k]+dp[k+1][j]); } } printf("Case #%d: %d\n",y,ans+dp[1][n]); } return 0; }