hdu 4283"You Are the One"(区间DP)
https://www.cnblogs.com/violet-acmer/p/9852294.html
题意:
有n个屌丝排成一排,每个屌丝都有一个不开心值a[ i ]( i=1,2,3,.....n ),如果第 i 个屌丝第 k 个上场,那么他的不开心度就是(k-1)*a[ i ]。
∑ni=1(ki-1)*a[i]的最小值,其中ki指的是第i个屌丝第k个上场。
关键条件"the director can put the boy into the dark room temporarily and let the boys behind his go to stage before him.",意思是导演可以通过将某个屌丝 i
之前的屌丝 j 放入小黑屋中使屌丝 i 在屌丝 j 前上场,不过这个小黑屋非常狭窄,先进入的最后上场,就像栈一样。
通过样例解释一下这句话:
假设有5的屌丝
id : 1 2 3 4 5
a[]: 5 8 3 9 4
按照当前的顺序,屌丝4是第4个上场的,如果想要让屌丝4第一个入场,那么,就需要将屌丝1,2,3依次放入小黑屋中,那么,屌丝1,2,3的上场顺序就是3,2,1。
题解:
定义变量dp[ i ][ j ] : ∑ji=1(ki-1)*a[i]的最小值( 1≤ki≤len,len=j-i+1(当前区间屌丝人数) )。
对于区间[ i, j ],屌丝 i 可以第 k 个上场,那么,其之后的相邻的 k-1 个屌丝一定在他之前全部上场,且他之前只有这 k-1 个屌丝上场,那么前 k 个屌丝的当前最小的
不开心度就是 (k-1)*a[ i ]+dp[ i+1 ][ i+k-1 ],那么余下的 len-k 个屌丝的最小不开心度就是 dp[ i+k ][ j ]+k*( sum(j)-sum(i+k-1) );(sum[ ]是屌丝不开心值的前缀和)。
所以dp转移方程就是 : dp[ i ][ j ]=min( dp[ i ][ j ],(k-1)*a[ i ]+dp[ i+1 ][ i+k-1 ] + dp[ i+k ][ j ]+k*( sum(j)-sum(i+k-1) ) );
AC代码:
1 #include<iostream> 2 #include<cstdio>| 3 #include<cstring> 4 using namespace std; 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 #define INF 0x3f3f3f3f 7 const int maxn=100+10; 8 9 int n; 10 int a[maxn]; 11 int dp[maxn][maxn]; 12 int sum[maxn]; 13 14 int Solve() 15 { 16 mem(dp,0); 17 for(int i=1;i < n;++i) 18 for(int j=i+1;j <= n;++j) 19 dp[i][j]=INF; 20 21 for(int len=2;len <= n;++len) 22 { 23 for(int i=1;i+len-1 <= n;++i) 24 { 25 int j=i+len-1; 26 for(int k=1;k <= (j-i+1);++k) 27 dp[i][j]=min(dp[i][j],(k-1)*a[i]+dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1])); 28 } 29 } 30 return dp[1][n]; 31 } 32 int main() 33 { 34 int t; 35 scanf("%d",&t); 36 for(int kase=1;kase <= t;++kase) 37 { 38 scanf("%d",&n); 39 sum[0]=0; 40 for(int i=1;i <= n;++i) 41 { 42 scanf("%d",a+i); 43 sum[i]=sum[i-1]+a[i]; 44 } 45 printf("Case #%d: %d\n",kase,Solve()); 46 } 47 return 0; 48 }