石子合并终极版 (GarsiaWachs算法) [o(n*n)] 板子

[SDOI2008] 石子合并

题目描述

在一个操场上摆放着一排 N N N 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 2 2 2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

试设计一个算法,计算出将 N N N 堆石子合并成一堆的最小得分。

输入格式

第一行一个整数 N N N

接下来 N N N 行,第 i i i 行一个整数 a i a_i ai,代表第 i i i 堆石子的石子数。

输出格式

输出将所有石子合并为一堆的最小得分。

样例 #1

样例输入 #1

4
1
1
1
1

样例输出 #1

8

提示

$ N \leq 40000, a_i \leq 200$

请注意 N N N 的范围

GarsiaWachs算法


设一个序列是A[0…n-1],
每次寻找最小的一个满足A[k-1]<=A[k+1]的k,
那么我们就把A[k]与A[k-1]合并,
ans += (A[k]+A[k-1])
之后从k向前寻找第一个满足A[j]>A[k]+A[k-1]的j,
把合并后的值A[k]+A[k-1]插入A[j]的后面。


板子

#include <bits/stdc++.h>
#define buff                     \
    ios::sync_with_stdio(false); \
    cin.tie(0);
//#define int long long
using namespace std;
const int N = 1000;
int n;
vector<int> s;

int func()
{
    int idx = s.size() - 2;

    for (int i = 0; i < s.size() - 2; i++)
    {
        if (s[i] <= s[i + 2])
        {
            idx = i;
            break;
        }
    }

    int tt = s[idx] + s[idx + 1];
    s.erase(s.begin() + idx);
    s.erase(s.begin() + idx);

    int idx2 = -1;

    for (int i = idx - 1; i >= 0; i--)
    {
        if (s[i] > tt)
        {
            idx2 = i;
            break;
        }
    }
    s.insert(s.begin() + idx2 + 1, tt);

    return tt;
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int t;
        cin >> t;
        s.push_back(t);
    }

    int ans = 0;
    for (int i = 1; i < n; i++)
        ans += func();

    cout << ans << '\n';
}
int main()
{
    buff;
    solve();
}
/*
设一个序列是A[0..n-1],
每次寻找最小的一个满足A[k-1]<=A[k+1]的k,
那么我们就把A[k]与A[k-1]合并,
ans += (A[k]+A[k-1])
之后从k向前寻找第一个满足A[j]>A[k]+A[k-1]的j,
把合并后的值A[k]+A[k-1]插入A[j]的后面。
*/
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joanh_Lan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值