Problem 2177 ytaaa
Accept: 221 Submit: 528
Time Limit: 2000 mSec Memory Limit : 32768 KB
Problem Description
Ytaaa作为一名特工执行了无数困难的任务,这一次ytaaa收到命令,需要炸毁敌人的一个工厂,为此ytaaa需要制造一批炸弹以供使用。 Ytaaa使用的这种新型炸弹由若干个炸药组成,每个炸药都有它的威力值,而炸弹的威力值为组成这个炸弹的所有炸药的最大威力差的平方,即(max-min)^2,假设一个炸弹有5个炸药组成,威力分别为5 9 8 2 1,那么它的威力为(9-1)^2=64。现在在炸弹的制造流水线上已经有一行n个炸药,由于时间紧迫,ytaaa并没有时间改变它们的顺序,只能确定他们的分组。作为ytaaa的首席顾问,请你帮助ytaaa确定炸药的分组,使制造出的炸弹拥有最大的威力和。
Input
输入由多组数据组成。第一行为一个正整数n(n<=1000),第二行为n个数,第i个数a[i]为第i个炸药的威力值(0<=a[i]<=1000)。
Output
对于给定的输入,输出一行一个数,为所有炸弹的最大威力和。
Sample Input
6
5 9 8 2 1 6
Sample Output
77
Source
FOJ有奖月赛-2014年11月
1、考虑dp,设定dp【i】表示分组进行到第i个炸弹,并且此时令第i个炸弹为此时小组的最后一个炸弹的威力最大值。
2、那么不难推出其状态转移方程:
dp【i】=max(dp【i】,dp【j-1】+(从j到i从最大值-从j到i最小值)^2)
表示我们从j到i分成当前这个小组。
那么我们要如何求从j到i的最大值和最小值呢?
①暴力点可以直接套个RMQ,ST算法直接搞即可。
②其实我套完RMQ就后悔了,我们这里可以直接从i-1一直扫到0,逆序处理,并且维护最大最小值即可。
搓比的套了ST算法的Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
using namespace std;
int a[1005];
int dp[1005];
int n;
int maxn[200005][20];
int minn[200005][20];
void ST()
{
int len=floor(log10(double(n))/log10(double(2)));
for(int j=1;j<=len;j++)
{
for(int i=1;i<=n+1-(1<<j);i++)
{
maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);
minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxn[i][0]=minn[i][0]=a[i];
}
ST();
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
int b=i;
int a=j;
int len= floor(log10(double(b-a+1))/log10(double(2)));
int tmp=max(maxn[a][len], maxn[b-(1<<len)+1][len])-min(minn[a][len], minn[b-(1<<len)+1][len]);
//printf("%d\n",tmp);
if(j==1)dp[i]=tmp*tmp;
else
{
dp[i]=max(dp[i],dp[j-1]+tmp*tmp);
}
}
}
printf("%d\n",dp[n]);
}
}