Fzu 2177 ytaaa【dp+RMQ--------ST】

来源:互联网 发布:算法第四版pdf 图灵 编辑:程序博客网 时间:2024/04/29 05:14

 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]);    }}






0 0
原创粉丝点击