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 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^2logn,不过想想实际,也就n^2的复杂度,因为这个复杂度,怕被卡时间,所以

也没什么信心打,结果跟队友码别的题,码到最后才发现思路错了,囧

view code//按比赛是想法做的,有点可惜,时间800ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int INF = 1<<30;
const int N = 5005;
int n,  dp[N][N];
ll sum[N], v[N],a[N];
bool vis[N][N];

int find(int l, int r, ll x)
{
    int n = r;
    while(l<=r)
    {
        int m = (l+r)>>1;
        if(sum[n]-sum[m-1]==x) return m;
        if(sum[n]-sum[m-1]>x) l = m+1;
        else r = m-1;
    }
    return 0;
}

int dfs(int l, int r)
{
    if(l>=r) return 0;
    if(vis[l][r]) return dp[l][r];
    vis[l][r] = 1;
    int &ans = dp[l][r];
    ans = v[r-l+1];
    for(int i=l; i<r; i++)
    {
        int R = find(i+1, r, sum[i]-sum[l-1]);
        if(!R) continue;
        ans = min((ll)ans, (ll)(dfs(i+1, R-1)+v[i-l+1]+v[r-R+1]));
    }
    return ans;
}

void solve()
{
    for(int i=1; i<=n; i++){
        scanf("%I64d", a+i);
        sum[i] = sum[i-1] + a[i];
    }
    for(int i=1; i<=n; i++) scanf("%I64d", v+i);
    memset(vis, 0, sizeof(vis));
    printf("%d\n", dfs(1,n));
}

int main()
{
//    freopen("in.txt", "r", stdin);
    while(scanf("%d", &n)>0 && n) solve();
    return 0;
}

根据比赛是想法的优化,思想差不多,只不过优化了时间空间

view code#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 5010;
int  L[N], R[N], cnt;
ll dp[N], sum[N], a[N], v[N], n;
bool vis[N];

int find(int l, int r, ll x)
{
    int n = r;
    while(l<=r)
    {
        int m = (l+r)>>1;
        if(sum[n]-sum[m-1]==x) return m;
        if(sum[n]-sum[m-1]>x) l=m+1;
        else r = m-1;
    }
    return 0;
}

void init()
{
    cnt = 0;
    for(int l=1; l<=n; l++)
    {
        int r = find(l+1, n, sum[l]);
        if(!r) continue;
        L[cnt] = l;
        R[cnt++] = r;
    }
}

ll dfs(int pos, int l, int r)
{
    if(l>=r) return 0;
    if(dp[l]!=-1) return dp[l];
    ll& ans=dp[l];
    ans = v[r-l+1];
    for(int i=pos; i<cnt; i++)
    {
        ans = min(dfs(i+1, L[i]+1,R[i]-1)+v[L[i]-l+1]+v[r-R[i]+1], ans);
    }
    return ans;
}

void solve()
{
    for(int i=1; i<=n; i++){
        scanf("%I64d", &a[i]);
        sum[i] = sum[i-1]+a[i];
    }
    for(int i=1; i<=n; i++) scanf("%I64d", v+i);
    init();
    memset(dp, -1, sizeof(dp));
    printf("%I64d\n",dfs(0, 1, n));
}

int main()
{
//    freopen("in.txt", "r", stdin);
    while(scanf("%I64d", &n)>0 && n) solve();
    return 0;
}

hdu 4960 Another OCD Patient(dp),布布扣,bubuko.com

时间: 2024-08-10 20:47:18

hdu 4960 Another OCD Patient(dp)的相关文章

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

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)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(记忆化搜索)

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

hdu 4960 Another OCD Patient(记忆化)

题目链接:hdu 4960 Another OCD Patient 题目大意:给定一个长度为n的序列,然后再给出n个数ai,表示合成i个数的代价.每次可以将连续的子序列和成一个数,即为序列中各个项的和.要求将给定长度n的序列变成一个回文串,一个数字只能被合成一次. 解题思路:dp[l][r]表示从l到r被和成回文串的最小代价,dp[l][r]=min(val(r?l+1),val(r?i+1)+val(j?l+1)+dp[j+1][i?1]),当i每减少1,对应的j一定变大,这一点可以减少大部分

hdu 4960 Another OCD Patient

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

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 记忆化搜索 DP

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

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