HDU 4960 (水dp)

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 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 

题意:给出一串数字,把这串数字合并成对称的串,合并连续的一段串有相应的花费,问最下花费是多少。

sl : 很水的dp,但是tle 好几发, 因为我是跳到了下一个状态还保留了当前的状态。但是想法还是对的。就是枚举两端相等的字段和。

这样就有转移方程 dp【i】【j】=min(dp【i+t】【j-x】 ,dp[i][j])  满足sigma(a[i] to a[i+t-1])==sigma(a[j-x+1] to a[j] ) .

开始傻比了的代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int MAX = 5000+10;
const int inf = 0x3f3f3f3f;
int dp[MAX][MAX]; LL sum[MAX];
int v[MAX],n,t[MAX],a[MAX];
inline void rdl(LL &n){
    n = 0;
    char c = getchar();
    while(c < ‘0‘ || c > ‘9‘) c = getchar();
    while(c >= ‘0‘ && c <= ‘9‘) n *= 10, n += (c - ‘0‘),c = getchar();
}
inline void rd(int &n){
    n = 0;
    char c = getchar();
    while(c < ‘0‘ || c > ‘9‘) c = getchar();
    while(c >= ‘0‘ && c <= ‘9‘) n *= 10, n += (c - ‘0‘),c = getchar();
}
int check(int L,int R,int d) {
    if(L+d==R) return 0;
    LL sum1=sum[L+d]-sum[L-1];
    LL sum2=0; int id=0;
    for(int i=R;i>L+d;i--) {
        sum2+=v[i];
        if(sum2>=sum1) {
            id=R-i;
            break;
        }
    }
    if(sum2==sum1) return id;
    else return -1;
}
int dfs(int L,int R) {
    if(L>=R) return 0;
    if(~dp[L][R]) return dp[L][R];
    int ans=inf; int d;
    for(int i=0;i<=(R-L);i++) {
        d=check(L,R,i);
        if(d!=-1) {
            ans=min(ans,dfs(L+i+1,R-d-1)+a[i+1]+a[d+1]);
        }
    }
    return dp[L][R]=ans;
}

int main() {
    while(scanf("%d",&n)==1&&n) {
        memset(sum,0,sizeof(sum));
        memset(dp,-1,sizeof(dp));
        for(int i=1;i<=n;i++) {
            rd(v[i]);
            sum[i]=sum[i-1]+v[i];
        }
        for(int i=1;i<=n;i++) {
            rd(a[i]);
        }
        int ans=dfs(1,n);
        printf("%d\n",ans);
    }
    return 0;

}

随便改过的代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int MAX = 5000+10;
int dp[MAX][MAX],a[MAX],v[MAX];
LL sum[MAX];
int dfs(int L,int R) {
    if(L>=R) return 0;
    if(~dp[L][R]) return dp[L][R];
    LL sum1,sum2; int ans=a[R-L+1];
    for(int i=L,j=R;i<j;) {
        sum1=sum[i]-sum[L-1];
        sum2=sum[R]-sum[j-1];
        if(sum1==sum2) {
            ans=min(ans,dfs(i+1,j-1)+a[i-L+1]+a[R-j+1]);
            i++; j--;
        }
        else if(sum1>sum2) j--;
        else i++;
    }
    return dp[L][R]=ans;
}
int main() {
    int n;
    while(scanf("%d",&n)==1&&n) {
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++) {
            scanf("%d",&v[i]);
            sum[i]=sum[i-1]+v[i];
        }
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        memset(dp,-1,sizeof(dp));
        int ans=dfs(1,n);
        printf("%d\n",ans);
    }

}

HDU 4960 (水dp),布布扣,bubuko.com

时间: 2024-08-24 16:19:47

HDU 4960 (水dp)的相关文章

HDU 4968 (水dp 其他?)

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <map> 6 using namespace std; 7 const int inf = 0x3f3f3f3f; 8 const int MAX = 200+10; 9 double GPA[10],dp1[20][30000],dp2[20][30000

hdu 4856 水dp

别看像搜索    试试就超时 ==,    想想还是用dp做吧: 因为只能从三个方向走   ,对于第一列只能从上往下走  所以很快就能求出第一列的dp[i][j] 到达表示这个位置的最大金币,对以后的每一列  先从左边过来更新一次,,,再有两种走法,往下走和往上走,用两个数组分别记下最大值   然后从这两个中找出最大值: #include<stdio.h> #include<string.h> #include<iostream> using namespace std

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)

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

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 记忆化搜索 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 4405 概率dp 2012年金华亚洲网络赛--虽然水,但是是自己独立做的第一道概率dp

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4405 e[i]:当前在位置i还需要走的步数期望 受刘汝佳的AC自动机那个后缀链接写法的启发,我的x[i]通过逆序算出来连续有"flight line "的时候,能到达的最远距离, rep(i,0,m) { scanf("%d%d",&xx,&yy); x[xx]=yy; } for(int i=n;i>=0;i--) if(x[i]!=-1 &

hdu 2571 命运(水DP)

题意: M*N的grid,每个格上有一个整数. 小明从左上角(1,1)打算走到右下角(M,N). 每次可以向下走一格,或向右走一格,或向右走到当前所在列的倍数的列的位置上.即:若当前位置是(i,j),可以走到(i,k*j) 问取走的最大和是多少. 思路: 水DP...边界的初始化要考虑.(因为有负数). 代码: int n,m; int a[30][1005]; int dp[30][1005]; int main(){ int T; cin>>T; while(T--){ cin>&g