zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    arrayObj.splice(start, deleteCount, [item1[, item2[, . . . [,itemN]]]])
    运算符 ||
    ajax 本地测试,使用Chrome 浏览器
    js set
    js get 传参 汉字 乱码问题
    删除对象中的key
    html 返回页面顶部
    js 设置回车事件
    盘面,盘口
    ST股
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15316494.html
Copyright © 2011-2022 走看看