【HDU】4960 Another OCD Patient 【DP】
2014-08-19 19:18
435 查看
传送门:【HDU】4960 Another OCD Patient
题目分析:比赛的时候写的太乱了,本来不需要合并的地方也合并了,现在重新改了改倒是清爽多了,顺便贴一下。
由于题目需要我们将原数组变成回文串,所以我们可以一开始就将原数组中必须合并的先合并了。那么什么是必须合并的呢?注意到左右对称,所以我们可以将左端的数相加正好等于右端的左右两个块分别合并(一定这样得到的是极小块),怎么相加呢?很简单,左边的数和比右边的小,左边再加一个数,右边的数和比左边的小,右边再加一个数,直到左右两边数相等时(合并)或者i>=j(退出)。
将得到的左右第 i 块中元素的数量用L[ i ]、R[ i ]表示,设得到左右得到的块数均为m(事实上左右的确是相等的)。
并设cost[ i ]为合并了i个元素的花费。
现在我们设dp[ i ]为添加了第L[ i ] 和R[ i ]块后形成回文串的最小花费。
dp[ i ] = min{ dp[ j - 1 ] + cost[ lnum[ j , i ] ] + cost[ rnum[ j , i ] ] | 1 <= j <= i , lnum[ j , i ]表示左边第j块到第i块元素个数总数,rnum[ j , i ]同理}。
最后再枚举中间合并的那一堆的数量,得到表达式minv = min{cost[ n ] , dp[ i ] + cost[ n - lnum[ i ] - rnum[ i ] ] | i <= m,lnum[ i ]表示从第1块到第i块的总元素个数,rnum[ i ]同理}。
代码如下:
题目分析:比赛的时候写的太乱了,本来不需要合并的地方也合并了,现在重新改了改倒是清爽多了,顺便贴一下。
由于题目需要我们将原数组变成回文串,所以我们可以一开始就将原数组中必须合并的先合并了。那么什么是必须合并的呢?注意到左右对称,所以我们可以将左端的数相加正好等于右端的左右两个块分别合并(一定这样得到的是极小块),怎么相加呢?很简单,左边的数和比右边的小,左边再加一个数,右边的数和比左边的小,右边再加一个数,直到左右两边数相等时(合并)或者i>=j(退出)。
将得到的左右第 i 块中元素的数量用L[ i ]、R[ i ]表示,设得到左右得到的块数均为m(事实上左右的确是相等的)。
并设cost[ i ]为合并了i个元素的花费。
现在我们设dp[ i ]为添加了第L[ i ] 和R[ i ]块后形成回文串的最小花费。
dp[ i ] = min{ dp[ j - 1 ] + cost[ lnum[ j , i ] ] + cost[ rnum[ j , i ] ] | 1 <= j <= i , lnum[ j , i ]表示左边第j块到第i块元素个数总数,rnum[ j , i ]同理}。
最后再枚举中间合并的那一堆的数量,得到表达式minv = min{cost[ n ] , dp[ i ] + cost[ n - lnum[ i ] - rnum[ i ] ] | i <= m,lnum[ i ]表示从第1块到第i块的总元素个数,rnum[ i ]同理}。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <math.h> using namespace std ; #define REP( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define REV( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define CLR( a , x ) memset ( a , x , sizeof a ) typedef long long LL ; const int MAXN = 5005 ; const int INF = 0x3f3f3f3f ; int a[MAXN] , cost[MAXN] ; int L[MAXN] , R[MAXN] , top ; int dp[MAXN] ; int n , m ; void solve () { top = 0 ; FOR ( i , 1 , n ) scanf ( "%d" , &a[i] ) ; FOR ( i , 1 , n ) scanf ( "%d" , &cost[i] ) ; for ( int i = 1 , j = n ; i < j ; ++ i , -- j ) { LL Lsum = a[i] , Rsum = a[j] ; int Lnum = 1 , Rnum = 1 ; while ( Lsum != Rsum ) { if ( i >= j ) break ; if ( Lsum < Rsum ) { ++ Lnum ; Lsum += a[++ i] ; } else { ++ Rnum ; Rsum += a[-- j] ; } } if ( Lsum == Rsum ) { ++ top ; L[top] = Lnum ; R[top] = Rnum ; } } FOR ( i , 1 , top ) { int tmp1 = 0 , tmp2 = 0 ; dp[i] = INF ; REV ( j , i , 1 ) { tmp1 += L[j] ; tmp2 += R[j] ; dp[i] = min ( dp[i] , dp[j - 1] + cost[tmp1] + cost[tmp2] ) ; } } int minv = cost , ans = n ; FOR ( i , 1 , top ) { ans -= L[i] + R[i] ; minv = min ( minv , dp[i] + cost[ans] ) ; } printf ( "%d\n" , minv ) ; } int main () { while ( ~scanf ( "%d" , &n ) && n ) solve () ; return 0 ; }
相关文章推荐
- hdu 4960 Another OCD Patient(dp)
- hdu 4960 Another OCD Patient(dp)2014多校训练第9场
- hdu 4960 Another OCD Patient dp(记忆化搜索)
- HDU-4960 Another OCD Patient (DP)
- HDU 4960(Another OCD Patient-区间dp)
- hdu 4960 Another OCD Patient 多校九 区间DP
- hdu 4960 Another OCD Patient(dp)2014多校训练第9场
- hdu 4960 Another OCD Patient dp(记忆化搜索)
- Another OCD Patient HDU - 4960 (dp+前缀和)
- HDU 4960 Another OCD Patient(DP)
- HDU 4960 Another OCD Patient (dp)
- HDU_4960 2014多校9 Another OCD Patient DP
- hdu 4960 Another OCD Patient(DP)
- HDU 4960 Another OCD Patient(记忆化搜索)
- 【DP】 HDOJ 4960 Another OCD Patient
- HDU 4960 Another OCD Patient(区间dp记忆化搜索)
- hdu 4960 Another OCD Patient
- hdu 4960 Another OCD Patient (最短路 解法
- HDU 4960 Another OCD Patient
- HDU 4960 Another OCD Patient 区间dp