暑假集训Day 10 小烈送菜

题目大意

小烈一下碰碰车就被乐满地的工做人员抓住了。做为扰乱秩序的惩罚,小烈必须去乐满地里的“漓江村”饭店端盘子。c++

服务员的工做很繁忙。他们要上菜,同时要使顾客们尽可能高兴。一位服务生为n个顾客上菜。这n个顾客坐成一排,小烈从一端的厨房中端出n盘菜(不要问我为何小烈能一会儿端住2500 盘菜,他就是能)为n个顾客各上一道相同的菜。算法

显然,小烈须要走一个来回,如图:spa

原本,小烈能够按1,2,3,...n的顺序一次给每一个顾客上菜,可是,聪明的小烈经过观察发现,每一个顾客都有一个开心值 H,离厨房最近的为H1 ,而后依次为\(H_2\),\(H_3\)...\(H_n\) 。若小烈给第j位顾客上菜前刚刚为第i位顾客上菜,则第j位就会高兴,产生高兴指数\(W_j =H_i*H_j\)。这样,若是小烈按必定的方式调整上菜顺序,能够获得更高的高兴指数。如今小烈想知道用某一方法可达到的n位顾客高兴指数之和的最大值S。由于顾客越高兴,给小烈的小费越多。第一位上菜的顾客不产生高兴值。code

输入格式

第一行一个整数n,顾客的数目。
第二行n个数,第i个数表示第i位顾客的开心值。各个数字用空格隔开。blog

输出格式

一个数s,为高兴指数的最大值。it

样例

样例输入

3
7 1 9

样例输出

72

算法分析

  • 这个题第一眼看上去好像没啥思路 虽然能一眼裸爆出是dp 可是状态和转移限制异常的多
  • 小烈要去一个来回 去的时候得到的权值回来的时候就不能得到了 那若是咱们将一个小烈劈开(仍是让他分身吧) 如今咱们有两个小烈 一块儿向前走 f[i][j]表示第一个小烈走到i 第二个小烈走到j并且此时前max(i,j)个客人都已经送好菜了,所能得到的最大值
  • 若是当前状态是i 如何转移到i+1呢? 由于i+1必需要由小烈a或者小烈b其中的一个去送 因此能够由多个状态转移过来
f[i+1][j] = max(f[i][j],f[i+1][j] + a[i+1]*a[i])//由i位置转移过来
f[i][i+1] = max(f[i][i+1],f[i][j] + a[i+1]*a[j])//由j位置转移过来
  • 可是这样的动态转移方程显然很ex,毕竟一堆限制条件 再来仔细品 由于要保证前max(i,j)的位置都要送到 因此f[i][j]和f[j][i]是等效的 毕竟谁在前面都同样
  • 因此咱们的状态转移方程就能够表示为
f[i+1][j] = max(f[i][j],f[i+1][j] + a[i+1]*a[i])
f[i+1][i] = max(f[i][i+1],f[i][j] + a[i+1]*a[j])

代码展现

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2500+10;
int a[maxn],f[maxn][maxn];

int main(){
	int n,ans = 0;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
	for(int i = 1;i <= n;++i)
		for(int j = 0;j < i;++j){
			f[i+1][j] = max(f[i][j] + a[i+1]*a[i],f[i+1][j]);
			f[i+1][i] = max(f[i][j] + a[i+1]*a[j],f[i+1][i]);
		}
	for(int i = 0;i < n;++i)ans = max(ans,f[n][i] + a[n]*a[i]);
	printf("%d",ans);
	return 0;
}
相关文章
相关标签/搜索