【HDU】4960 Another OCD Patient 【DP】

2024-09-05 15:08
文章标签 dp hdu another patient 4960 ocd

本文主要是介绍【HDU】4960 Another OCD Patient 【DP】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门:【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 ]同理}。


代码如下:


#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[n] , 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】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139299

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while