zoukankan      html  css  js  c++  java
  • 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
    ",kase,Solve());
    46     }
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    [算法]位运算问题之二
    [算法]位运算问题之一
    [算法]海量数据问题之二
    [算法]海量数据问题之一
    [算法]旋转词问题
    [算法]去掉字符串中连续出现的k个0子串
    [算法]字符串中数字子串的求和
    [算法]字符串之变形词问题
    Linux常用命令
    数据库中的事物
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10127128.html
Copyright © 2011-2022 走看看