• P5569 [SDOI2008] 石子合并 解题报告


    P5569 [SDOI2008] 石子合并解题报告:

    题意

    (n) 个石子排成一排,第 (i) 堆有 (a_i) 个,每次可以选取两个石子堆合并,得分是新石子堆的大小,求合并所有石子为一堆的最小得分。

    (nleqslant 40000)

    分析

    大众科技,GarsiaWachs 算法。

    设当前石子共 (w) 堆,分别为 (v_{1cdots w})

    1. 找到最小的 (k) 满足 (v_{k-1}<v_{k+1}),然后找到最大的 (p) 满足 (p<k)(v_p>v_k+v_{k-1})
    2. 合并第 (k,k+1) 堆石子,并将其放在第 (p) 堆石子后面;
    3. 重复操作直到 (w=1)

    证明鸽了。

    注意要在序列两端放置两个哨兵点。

    复杂度:(O(n^2)),开 O2 能过,可以用平衡树优化到 (O(nlog n))

    实际上有一个扩展,但是我还不会。

    代码

    #include<stdio.h>
    #include<vector>
    #define inf 2000000000
    using namespace std;
    const int maxn=40005;
    int n,ans;
    int a[maxn];
    vector<int>v;
    int main(){
    	scanf("%d",&n);
    	v.push_back(inf);
    	for(int i=1,x;i<=n;i++)
    		scanf("%d",&x),v.push_back(x);
    	v.push_back(inf);
    	for(int i=1;i<n;i++){
    		int k=0,p=0,rec=0;
    		for(int j=1;j<=n;j++)
    			if(v[j-1]<v[j+1]){
    				k=j;
    				break;
    			}
    		rec=v[k]+v[k-1],ans+=rec;
    		for(int j=k-1;j>=0;j--)
    			if(v[j]>rec){
    				p=j;
    				break;
    			}
    		v.erase(v.begin()+k),v.erase(v.begin()+(k-1)),v.insert(v.begin()+p+1,rec);
    	}
    	printf("%d
    ",ans); 
    	return 0;
    }
    
  • 相关阅读:
    Owin
    C#不区分大小写的字符串替换(Replace)函数
    如何创建测试程序调试nginx数据结构
    一张脑图说清 Nginx 的主流程
    gdb常用命令记录
    nginx的configure流程
    c 编译器大全
    PHP 的 uniqid 函数产生的 id 真的是唯一的么?
    UUID那些事
    PHP 编码规范
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15316494.html
Copyright © 2020-2023  润新知