HDU4960Another OCD Patient(区间dp,分块后再DP)

Another OCD Patient

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 716    Accepted Submission(s): 270

Problem Description

Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xiaoji is an OCD patient,
he can‘t stand with the disorder of the volume of the N pieces of plasticene. Now he wants to merge some successive pieces so that the volume in line is symmetrical! For example, (10, 20, 20, 10), (4,1,4) and (2) are symmetrical but (3,1,2), (3, 1, 1) and
(1, 2, 1, 2) are not.

However, because Xiaoji‘s OCD is more and more serious, now he has a strange opinion that merging i successive pieces into one will cost ai. And he wants to achieve his goal with minimum cost. Can you help him?

By the way, if one piece is merged by Xiaoji, he would not use it to merge again. Don‘t ask why. You should know Xiaoji has an OCD.

Input

The input contains multiple test cases.

The first line of each case is an integer N (0 < N <= 5000), indicating the number of pieces in a line. The second line contains N integers Vi, volume of each piece (0 < Vi <=10^9). The third line contains N integers ai
(0 < ai <=10000), and a1 is always 0.

The input is terminated by N = 0.

Output

Output one line containing the minimum cost of all operations Xiaoji needs.

Sample Input

5
6 2 8 7 1
0 5 2 10 20
0

Sample Output

10

Hint

In the sample, there is two ways to achieve Xiaoji‘s goal.
[6 2 8 7 1] -> [8 8 7 1] -> [8 8 8] will cost 5 + 5 = 10.
[6 2 8 7 1] -> [24] will cost 20.

 

Author

SYSU

Source

2014 Multi-University Training Contest 9

题意:给出n个数,把这n个数合成一个对称的集合。第三行代表一次合成i个数需要花费a[i],求出最小的花费。

解题:先把n个数合成一个对称集合共k个块,再进行对称区间DP。

#include<stdio.h>
__int64 v[5005],a[5005],pre[5005],dp[5005];
void dfs(int l,int r)//分块,使[l,r]对称
{
    int i=l,j=r;
    __int64 suml=v[l],sumr=v[r];
    while(i<j)
    {
        if(suml==sumr)
        {
            if(i+1<=j-1)dfs(i+1,j-1);
            pre[l]=i; pre[j]=r;//区间最左最右块和相等
             return ;
        }
        if(suml<sumr)suml+=v[++i];
        else sumr+=v[--j];
    }
    pre[l]=r;//一个区间只能合成一块
}
void count(int k)//分成k个块后,从最中间块向两边扩大范围进行DP,pre[i]表示从第一块到
{
    int l, r,m;
    if(k%2)
        {
            l=k/2; r=k/2+2; m=k/2+1;//m是最中间块
            dp[m]=a[pre[m]-pre[m-1]];
        }
    else
        {
            l=k/2; r=k/2+1; m=l; dp[l]=0;
        }
    while(r<=k)
        {
            dp[r]=a[pre[r]-pre[l-1]];//合成一大块时
            for(int tr=r,tl=l;m<tr;tr--,tl++)//在区间块找出对应的最小dp[r]
            if(dp[r]>dp[tr-1]+a[pre[r]-pre[tr-1]]+a[pre[tl]-pre[l-1]])
            dp[r]=dp[tr-1]+a[pre[r]-pre[tr-1]]+a[pre[tl]-pre[l-1]];
            l--;r++;//向两边扩增
        }
}
int main()
{
    int n,i,k;
    __int64 tk;
    while(scanf("%d",&n)>0&&n)
    {
        for( i=1;i<=n;i++)scanf("%I64d",&v[i]);
        for( i=1;i<=n;i++)scanf("%I64d",&a[i]);
        dfs(1,n);
        k=0; i=1;pre[0]=0;
        while(i<=n)//把一整块缩成一个点,pre[k]变成前k个块共有多少个数组成k块
        {
            tk=pre[i]-i+1; i=pre[i]+1; ++k; pre[k]=tk+pre[k-1];
        }
        count(k);
        printf("%I64d\n",dp[k]);
    }
}

HDU4960Another OCD Patient(区间dp,分块后再DP),布布扣,bubuko.com

时间: 2024-10-28 23:01:00

HDU4960Another OCD Patient(区间dp,分块后再DP)的相关文章

HDU 4960 Another OCD Patient 区间dp

区间dp.. T^T一直感觉是n^3,看了题解看来是数据水了么.. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string.h> #define ll long long #define inf 1e8 inline int min(int a, int b){return a<b?a:b;} inline void rdl(ll

HDU 4960 Another OCD Patient(区间dp记忆化搜索)

题目大意:给你一串数字让你判断经过若干次合并,使得这个数字串变成回文串的最小成本是多少.第一行是数字串,第二行是合并连续i个数字的成本是多少. 解题思路:区间dp,可以进行记忆化搜索,如果左边比右边和大那么右边一定是小了,右边比左边大那么左边一定小了.因为保证有解.具体不太好说,直接看代码吧. Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe

hdu 4960 Another OCD Patient(dp)2014多校训练第9场

Another OCD Patient                                                                         Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) pat

hdu 4960 Another OCD Patient(dp)

Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 645    Accepted Submission(s): 238 Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This mornin

HDU 4960 Another OCD Patient 简单DP

思路: 因为是对称的,所以如果两段是对称的,那么一段的前缀和一定等于另一段的后缀和.根据这个性质,我们可以预处理出这个数列的对称点对.然后最后一个对称段是从哪里开始的,做n^2的DP就可以了. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algori

天啊,竟然忘了买春节后回上海的票。。。只能买区间票,中途再补票了。。。

天啊,竟然忘了买春节后回上海的票...只能买区间票,中途再补票了... 今年火车票预售期提前了60天,买了回家的票,但是由于平时工作太忙,忘了买返程票,天呀... 今天早上马上看下还有没有票了,马上看下到中途的区间票,还好还有,马上订下,离开始卖初六的返程票已经过去了一个礼拜了才记起来要订票... 来上海快5年了,这里除了空气不好,其他都还可以 虽然很多次想回家发展,但是毕竟家里和上海差距太大了,而且这么些年来,已经不适应农村那种环境了 什么时候存款100万就回老家吧...在上海混成这样,太没出

HDU_4960 2014多校9 Another OCD Patient DP

其实现在想起来是个巨简单的DP,模型就跟LCS很像,比赛的时候居然没想出来,在聪哥提醒下还卡了个地方 就是说给定一串n个数字的序列,可以连续合并,最终使得序列是回文的,题目也给定了合并数字所需的代价,合并一个为0,合并2个 3个..n个的代价都有 题目比较新意的地方就是回文,这也是我们要解决的主要地方,回文..其实用前缀和+后缀和就可以解决了... 用记忆化搜索写起来比较方便,每次对于求的L和R,枚举i,j,使得 L-i合并之后可以与j-R合并之后回文,然后递归处理i和j即可. #include

HDU4960:Another OCD Patient

Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xiaoji is an OCD patie

HDU 4960 Another OCD Patient(记忆化搜索)

HDU 4960 Another OCD Patient 题目链接 记忆化搜索,由于每个碎片值都是正数,所以每个前缀和后缀都是递增的,就可以利用twopointer去找到每个相等的位置,然后下一个区间相当于一个子问题,用记忆化搜索即可,复杂度接近O(n^2) 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int INF = 0x3f3f3f