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

 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值