先把两个题都贴出来看看吧
An old Stone Game
Time Limit: 5000MS | Memory Limit: 30000K | |
Total Submissions: 3383 | Accepted: 940 |
Description
There is an old stone game.At the beginning of the game the player picks n(1<=n<=50000) piles of stones in a line. The goal is to merge the stones in one pile observing the following rules:
At each step of the game,the player can merge two adjoining piles to a new pile.The score is the number of stones in the new pile.
You are to write a program to determine the minimum of the total score.
At each step of the game,the player can merge two adjoining piles to a new pile.The score is the number of stones in the new pile.
You are to write a program to determine the minimum of the total score.
Input
The input contains several test cases. The first line of each test case contains an integer n, denoting the number of piles. The following n integers describe the number of stones in each pile at the beginning of the game.
The last test case is followed by one zero.
The last test case is followed by one zero.
Output
For each test case output the answer on a single line.You may assume the answer will not exceed 1000000000.
Sample Input
1 100 3 3 4 3 4 1 1 1 1 0
Sample Output
0 17 8
基准时间限制:2 秒 空间限制:131072 KB 分值: 320
难度:7级算法题
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
Input
第1行:N(2 <= N <= 50000) 第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4 1 2 3 4
Output示例
19
因为数据量的关系,四边形不等式的优化dp是不行的。
然后到网上看到了神奇的GarsiaWachs算法
看了半天也不太懂= =
做法就是,比如序列是a[n],从前往后寻找,找到k满足a[k]<a[k+2],然后合并a[k]和a[k+1],替换为新值s,然后从k往前寻找,找到第一个大于s的数,并把s插到那个数的后面。
理论上来说,这个算法是n^2的。但因为前面的常数很小所以是可以过的。或者用平衡树优化= = 我这个辣鸡并不会。。。
具体的可以看看这个博客 http://fanhq666.blog.163.com/blog/static/81943426201062865551410/
代码转自ACdream巨巨。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 50005;
int stone[N];
int n,t,ans;
void combine(int k)
{
int tmp = stone[k] + stone[k-1];
ans += tmp;
for(int i=k;i<t-1;i++)
stone[i] = stone[i+1];
t--;
int j = 0;
for(j=k-1;j>0 && stone[j-1] < tmp;j--)
stone[j] = stone[j-1];
stone[j] = tmp;
while(j >= 2 && stone[j] >= stone[j-2])
{
int d = t - j;
combine(j-1);
j = t - d;
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n == 0) break;
for(int i=0;i<n;i++)
scanf("%d",stone+i);
t = 1;
ans = 0;
for(int i=1;i<n;i++)
{
stone[t++] = stone[i];
while(t >= 3 && stone[t-3] <= stone[t-1])
combine(t-2);
}
while(t > 1) combine(t-1);
printf("%d\n",ans);
}
return 0;
}