Hot Start Up (hard version)

这道题目是一个将一条序列分成两个子序列并且要求目标结果最优的问题,有一个通用的状态表示方法,当第i个物品放入其中一条序列后另一条序列的末尾元素是什么?

在本题当中按照题意本应该定义f[i][j][k]表示放完第i个物品并且第一条序列末尾是j并且第二条序列末尾是k时最小的花费,这样会变成O(n^3)的时间复杂度,但是放完第i个物品时就可以知道其中一个的末尾元素了,因此数组变成f[i][j],表示放完第i个物品后其中一条序列后另一条子序列的结尾是j时的最小花费。

由此得到两条状态转移方程,分别是第i个物品放在第i-1个物品后面时,以及第i个物品不放在第i-1个物品后面时.
所以可以得到:

f[i][j] = max(f[i][j] , f[i - 1][j] + ((a[i] == a[i - 1] )? cold[a[i]] - hot[a[i]] : 0)) ;
f[i][a[i - 1]] = max(f[i][a[i - 1]] , f[i - 1][j] + ((a[i] == j) ? cold[a[i]] - hot[a[i]] : 0 )) ;

 

这个转移很明显可以直接线段树找区间最小值加上单点查询和单点修改来完成 

#include<bits/stdc++.h>
using namespace std ;
#define maxn 5100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
    while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
    return ans * f ;
}
int n , t , k ; 
int cold[maxn] , hot[maxn] ; 
int f[maxn][maxn] ; 
int a[maxn]  ;
signed main(){
    t = read() ; 
    while(t--){
        n = read() , k = read() ; 
        for(int i = 0 ; i <= n ; i++)    
            for(int j = 0 ; j <= k ; j++)
                f[i][j] = -1000000000; 
        for(int i = 1 ; i <= n ; i++)
            a[i] = read() ; 
        for(int i = 1; i <= k ; i++)
            cold[i] = read() ; 
        for(int j = 1 ; j <= k ; j++)
            hot[j] = read() ; 
        f[0][0] = 0; 
//        for(int i = 1 ; i <= k ; i++)
//            f[0][i] = -99999999 ; 
        for(int i = 1 ; i <= n ; i++){
            for(int j = 0 ; j <= k ; j++){ 
                f[i][j] = max(f[i][j] , f[i - 1][j] + ((a[i] == a[i - 1] )? cold[a[i]] - hot[a[i]] : 0)) ; 
                f[i][a[i - 1]] = max(f[i][a[i - 1]] , f[i - 1][j] + ((a[i] == j) ? cold[a[i]] - hot[a[i]] : 0 )) ; 
//                printf("f[%lld][%lld]  : %lld \n" , i , j , f[i][j]) ; 
//                printf("f[%lld][%lld] : %lld \n"  , i , a[i - 1] , f[i][a[i - 1]]) ; 
//                printf("a[i] : %lld a[i - 1] : %lld a[i] : %lld j : %lld \n" , a[i] , a[i - 1] , (a[i] == a[i - 1] )? cold[a[i]] - hot[a[i]] : 0 , j) ; 
            }
        }
//        for(int i = 1 ; i <= n ; i++)
//            for(int j = 0 ; j <= k ; j++)
//                printf("f[%lld][%lld]  : %lld \n" , i , j , f[i][j]) ; 
        int ans = 0; 
        for(int i = 0 ; i <= k ; i++)
            ans = max(ans , f[n][i]) ; 
        ans = -ans ; 
        for(int i = 1 ; i <= n ; i++)
            ans += cold[a[i]]  ; 
        printf("%lld\n" , ans) ; 
    }
    return 0 ;
 }

 

posted @ 2023-03-02 22:20  Vellichor_zht  阅读(64)  评论(0)    收藏  举报