ACM_成绩单(区间dp套dp)

#2292. 「THUSC 2016」成绩单

这一看就知道是dp阿(自信!

而且还能看出是区间dp哼哼

第一思路:

每次都取子序列,可以设一个\(f(i,j)\)

其值表示删掉区间\([i,j]\)所需的最小代价

好!然后就不会转移了。

其实,每一次取的代价都是相互独立的,

所以对于拥有同样值域的子列,取走的代价的都是一样的

可以设出\( dp( l , r , i  , j ) \)表示从i到j的转移

域是\( [l,r]\),这个dp组的值就是删掉\( [i,j]\)中若干个数后能使剩下的数都在域内的最小代价;

给出\(G(i,j)\)为删掉此区间所有数的最小代价。

这样我们就可以转移了

\(dp[l][k][ min(i,w[k]) ][ max(j,w[k]) ]=min(dp[min(k,w[j+1])][max(l,w[i+1])][i][j+1],dp[k][l][i][j])\)

\(G[l][r]=dp[l][r][i][j]+A+B*(r-l)*(r-l)\)

\( dp[k][l][i][t]=min(dp[k][l][i][t],dp[k][l][i][t]+G[i+1][t]) \)

\( dp[l][r][i][j]=min(G[i][k]+dp[l][r][k+1][j],dp[l][r][i][j]+dp[l][r][k+1][j]) \)

加个离散化

然后余下的到n继续维护就可以了,

#pragma comment(linker,"/STACK:1024000000,1024000000")
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <experimental/string_view>
#define lodou long double
#define lll __int128
#define INmF 0x3f3f3f3f
#define lbt(x) (x&(-x))
#define mes(a,b) memset(a,b,sizeof(a))
#define qwq(a,b) for(int i=a ;i<=b;++i)
#define qeq(a,b) for(int j=a ;j<=b;++j)
#define IOS ios::sync_with_stdio(false)
#define UPCASE( c ) ( ((c) >= 'c' && (c) <= 'z') ? ((c) - 0x20) : (c) )
#define pb push_back
#define mkp make_pair
using namespace std;
using namespace __gnu_pbds;

using pii=pair<int,int>;
using Balanced_Tree=tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>;
Balanced_Tree seq;

const double Eps = 1e-8 ;
const double pi  = acos(-1) ;
const long long mod = 1e9+7 ;
typedef long long int ll;


inline ll pow_mod (ll a,ll b) {ll res=1;a%=mod; if(b<0) return -1; for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
inline ll fas_mul (ll a,ll b) { return ( (a*b-(ll)(((long double)a*b+0.5)/mod)*mod)%mod+mod)%mod ; }


namespace io {

    #define _ read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('\n')

    #define I_int __int128
    inline I_int read() {
        I_int x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        if( x == 0 ) { putchar( '0' ) ; return ; }
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar ( F[ -- cnt ] ) ;
    }
    #undef I_int

}using namespace io ;

const int Maxn = 55 ;
int w[Maxn]={0} , por[Maxn] ;
int dp[Maxn][Maxn][Maxn][Maxn] ,
    G[Maxn][Maxn] ;
int main()
{
  int n=_ , A=_ , B=_ ;
  int bz = n*A  , tot=0 ;
  qwq( 1 , n )
  {
      w[i]=_;
      por[++tot]=w[i] ;
  }
  sort( por+1 , por+tot+1 ) ;
  tot = unique( por+1 , por+tot+1 )-por-1 ;
  qwq( 1 , n )
    w[i] = lower_bound( por+1 , por+tot+1 , w[i] ) -por ;
  
  mes( dp , INmF ) ;
  mes( G , INmF ) ;
  qwq( 1 , n )
  	dp[i][i][w[i]][w[i]]=0 ,
    G[i][i-1] = 0 ;

    
  for( int l=n ; l>=1 ; --l )
    for( int r=l ; r<=n ; ++r )
    {
      qwq( 1 , tot )
        qeq( 1 , tot )
        {
          if( dp[l][r][i][j]>=bz )
            continue ;
          G[l][r] = min( dp[l][r][i][j]+A+B*(por[j]-por[i])*(por[j]-por[i]),G[l][r] );
          for( int k=r+1 ; k<=n ; ++k )
            dp[l][k][ min(i,w[k]) ][ max(j,w[k]) ] = min( dp[l][k][ min(i,w[k]) ][ max(j,w[k]) ] ,dp[l][r][i][j]+G[r+1][k-1] );
        }
		for( int k=r+1 ; k<=n ; ++k )//余列需要维护
		  	G[l][k] = min( G[l][k] , G[l][r]+G[r+1][k] );
    }
	outn( G[1][n] ) ;
}

 

 

喜欢这篇文章吗,不妨分享给朋友们吧!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值