• vijos & codevs 能量项链


    描述

    在Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有N颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为(Mars单位),新产生的珠子的头标记为m,尾标记为n。

    需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

    例如:设N=4,4颗珠子的头标记与尾标记依次为(2,3) (3,5) (5,10) (10,2)。我们用记号⊕表示两颗珠子的聚合操作,(j⊕k)表示第j,k两颗珠子聚合后所释放的能量。则第4、1两颗珠子聚合后释放的能量为:
    (4⊕1)=10*2*3=60。

    这一串项链可以得到最优值的一个聚合顺序所释放的总能量为
    ((4⊕1)⊕2)⊕3)=10*2*3+10*3*5+10*5*10=710。

    格式

    输入格式

    输入文件的第一行是一个正整数N(4≤N≤100),表示项链上珠子的个数。第二行是N个用空格隔开的正整数,所有的数均不超过1000。第i个数为第i颗珠子的头标记(1≤i≤N),当1≤i<N时,第i颗珠子的尾标记应该等于第i+1颗珠子的头标记。第N颗珠子的尾标记应该等于第1颗珠子的头标记。

    至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

    输出格式

    输出文件只有一行,是一个正整数E(E≤2.1*109),为一个最优聚合顺序所释放的总能量。

    样例1

    样例输入1

    4
    2 3 5 10

    样例输出1

    710

    限制

    1s

    来源

    NOIP2006第一题

    (转自Vijos1312,题目传送门[codevs]&[vijos])


      这道题和加分二叉树有点像,所以立刻想到区间dp。它们俩的差别大概就在一个是树上,还有一个是在环上。处理环就像骑士那样处理,破环成链,特殊处理两端。于是用f[aflag][i][j]来进行dp.

      (PS,下文的区间指的是项链上的一段,[i, j]表示第i个能量珠到第j个能量珠这一段)

      其中aflag为0时表示是在链上,[i, j]区间的能量珠合并出来的最大值。当aflag为0时表示过剖开点,从j到i(区间[j, n][1, i])。

      在链上的比较简单,很容易可以想出方程 f[0][i][j] = max{f[0][i][k] + f[0][k + 1][j] + a[i] * a[k + 1] + a[(j + 1) % n]}(a表示读入的n个数,下标从0开始)

      过剖开点就有三种情况

    1. k在左端,f[1][i][j] = max{f[0][k][i] + f[1][k - 1][j] + a[(i + 1) % n] * a[k] * a[j]}

    2. k在右端,f[1][i][j] = max{f[0][j][k] + f[1][i][k + 1] + a[j] * a[k + 1] * a[(i + 1) % n]}
    3. 刚好是两个在链上的区间(区间[j, n][1, i])合并,smax(f[1][i][j], f[0][0][i] + f[0][j][n - 1] + a[j] * a[0] * a[i + 1])

     最后在f[0][0][n - 1]f[1][i][i + 1]中找找最大值就好了。

    Code

      1 /**
      2  * codevs        & vijos.org
      3  * Problem#1154    & 1312
      4  * Accepted        & Accepted
      5  * Time:13ms    & 30ms
      6  * Memory:364k    & 536k
      7  */ 
      8 #include<iostream>
      9 #include<sstream>
     10 #include<cstdio>
     11 #include<cmath>
     12 #include<cstdlib>
     13 #include<cstring>
     14 #include<cctype>
     15 #include<queue>
     16 #include<set>
     17 #include<map>
     18 #include<stack>
     19 #include<vector>
     20 #include<algorithm>
     21 using namespace std;
     22 typedef bool boolean;
     23 #define smin(a, b) (a) = min((a), (b))
     24 #define smax(a, b) (a) = max((a), (b))
     25 template<typename T>
     26 inline void readInteger(T& u){
     27     char x;
     28     int aFlag = 1;
     29     while(!isdigit((x = getchar())) && x != '-');
     30     if(x == '-'){
     31         aFlag = -1;
     32         x = getchar();
     33     }
     34     for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
     35     ungetc(x, stdin);
     36     u *= aFlag;
     37 }
     38 
     39 template<typename T>class Matrix{
     40     public:
     41         T *p;
     42         int lines;
     43         int rows;
     44         Matrix():p(NULL){    }
     45         Matrix(int rows, int lines):lines(lines), rows(rows){
     46             p = new T[(lines * rows)];
     47         }
     48         T* operator [](int pos){
     49             return (p + pos * lines);
     50         }
     51 };
     52 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows)
     53 
     54 #define idx(i)    a[(i + n) % n]
     55 
     56 int n;
     57 int *a;
     58 Matrix<int> f[2];
     59 
     60 inline void init(){
     61     readInteger(n);
     62     f[0] = Matrix<int>(n, n);
     63     f[1] = Matrix<int>(n, n);
     64     a = new int[(const int)(n)];
     65     for(int i = 0; i < n; i++)
     66         readInteger(a[i]);
     67 }
     68 
     69 inline void solve(){
     70     matset(f[0], 0xf0, sizeof(int));
     71     matset(f[1], 0xf0, sizeof(int));
     72     for(int i = 0; i < n - 1; i++){
     73         f[0][i][i + 1] = a[i] * a[i + 1] * idx(i + 2);
     74     }
     75     for(int i = 0; i < n; i++)    f[0][i][i] = 0;
     76     f[1][0][n - 1] = a[n - 1] * a[0] * a[1];
     77     for(int s = 2; s < n; s++){
     78         for(int i = 0; i + s < n; i++){
     79             int j = i + s;
     80             for(int k = i; k < j; k++){
     81                 smax(f[0][i][j], f[0][i][k] + f[0][k + 1][j] + a[i] * a[k + 1] * idx(j + 1));
     82             }
     83         }
     84         for(int i = 0; i - s < 0; i++){
     85             int j = (i - s + n) % n;
     86             for(int k = i; k > 0; k--){
     87                 smax(f[1][i][j], f[0][k][i] + f[1][k - 1][j] + idx(i + 1) * a[k] * a[j]);
     88             }
     89             for(int k = j; k < n - 1; k++){
     90                 smax(f[1][i][j], f[0][j][k] + f[1][i][k + 1] + a[j] * a[k + 1] * idx(i + 1));
     91             }
     92             smax(f[1][i][j], f[0][0][i] + f[0][j][n - 1] + a[j] * a[0] * a[i + 1]);
     93         }
     94     }
     95     int result = f[0][0][n - 1];
     96     for(int i = 0; i < n - 1; i++){
     97         smax(result, f[1][i][i + 1]);
     98     }
     99     cout << result;
    100 }
    101 
    102 ///Main Funtion
    103 int main(int argc, char* argv[]){
    104     init();
    105     solve();
    106     return 0;
    107 }
  • 相关阅读:
    asp.net 生成PDF方法
    C# 缓存学习总结
    C# 缓存学习第一天
    C# 文件管理类 Directory
    C# 链接Sql和Access数据库语句
    SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn(实战篇)之AlwaysOn可用性组搭建
    SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn(实战篇)之建立活动目录域、DNS服务器和Windows故障转移群集(准备工作)
    SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn可用性组(理论篇)
    SQL Server ->> 利用CONVERT/STR/FORMAT函数把浮点型数据格式化/转换成字符串
    SQL Server ->> Computed Column(计算列)
  • 原文地址:https://www.cnblogs.com/yyf0309/p/6129162.html
Copyright © 2020-2023  润新知