您的位置:首页 > 其它

HDU 4960 Another OCD Patient

2014-08-20 17:45 495 查看
题意:给出一串数字,让你对相邻的几项合并,使最后合并后的序列为对称的序列。同时对不同个数的数字合并有个不同的费用。求最小的消耗费用。

思路:比赛中总是想如何求出对称的序列,怎么也想不出办法。其实,若对称的话,左右两端的序列必须各有一段和是相同的,而且这个子序列是固定的。如果想到这一个点。题目就简单了。

首先,我们可以预处理出左右两端子序列和相等的位置。这些节点就是让合并后的序列为对称序列的关键节点.

我们对关键节点进行标号,左右两端的关键节点形成一对,同时保存和上一个关键节点的长度(即能形成对称的子序列的长度)

对于每个节点,我们可以求出当序列处理到该处时,所需的最小费用。

则dp[i] = min(dp[j] + a[suml[i] - sum[j]] + a[sumr[i] - sumr[j]])

其中:suml[i]表示到左端第i个关键节点的左面的数字的个数,sumr[i]表示到右端第i个关键节点的右面的数字的个数。

而,最终的结果,就是对于每个dp[i], dp[i] + 剩余节点直接全部合成一个数的费用 , 中的最小值。

这里还有一个小的问题,因为对称性分为奇对称和偶对称,这里该如何处理?在这里,其实我们可以把偶对称看做在整个序列关于中间的空的序列的奇对称,就可以用上面的方法解。

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAX = 5050;

long long a[MAX];
long long v[MAX];
long long s1[MAX];
long long s2[MAX];
long long sum1[MAX];
long long sum2[MAX];
int sz;
int odd;
long long dp[MAX];
int N;

void pre_work()
{
sz = odd =0;
int begin = 1, end = N;
int lsum = a[begin], rsum = a[end];
while(true){
int l = begin,r = end;
while(l != r && lsum != rsum){
if(lsum < rsum)
lsum += a[++l];
else if(rsum < lsum)
rsum += a[--r];
}
if(l == r){
odd = end - begin + 1;
return;
}
else{
s1[++sz] = l - begin + 1;
s2[sz] = end - r + 1;
if(r == l + 1)
return;
begin = l + 1;
end = r - 1;
lsum = a[begin];
rsum = a[end];
}
}

}

int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d",&N)&&N){
for(int i = 1; i <= N; ++i)
scanf("%I64d", a+i);
for(int i = 1 ; i <= N; ++i)
scanf("%I64d",v + i);
pre_work();

sum1[0] = sum2[0] = 0;
for(int i = 1; i <= sz; ++i){
sum1[i] = sum1[i-1] + s1[i];
sum2[i] = sum2[i-1] + s2[i];
}
//for(int i = 1; i <= sz; ++i)
//    printf("%I64d %I64d\n",sum1[i],sum2[i]);
if(sz == 0){
printf("%I64d\n",v
);
continue;
}
memset(dp,0x3f,sizeof(dp));
long long ans = 0x3f3f3f3f3f3f3f3f;
dp[0] = 0;
for(int i = 1; i <= sz; ++i){
for(int j = 0; j < i; ++j)
dp[i] = min(dp[i],dp[j] + v[sum1[i] - sum1[j]] + v[sum2[i] - sum2[j]]);
ans = min(ans,dp[i] + v[N - sum1[i]- sum2[i]]);
//printf("%d\n",ans);
}
//for(int i = 1; i <= sz; ++i)
//     printf("%I64d\n",dp[i]);
printf("%I64d\n",ans);
}
return 0;
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: