1744:ジャンプ階段


1744:ステップジャンプ

期限:1000ミリ秒のメモリの制限:131072キロバイト

タイトル説明

コース側行のN個のステップ、i番目のステップがHi(0 <Hi≤109)は、0番目のステップの高さはまた、ありますグランドゼロからの高さがあります。

N SA、SB(NULLであることができる)、集合S =ためのステップの2つのセットにステップを置くつもりポロ{P1、P2、... | Sを|、P}、 P1 <P2 <... < P | S |、彼がかかります


\(\ sum_ {1} ^ {S} \左| Hpの[I] -HP [I-1] \右| \)

物理量の完全に。

今、彼は必要な全体的な力の倍の最小値をジャンプしたい、あなたは彼を助けることができますか?

[入力]

行Nの最初の数

Nの第2行は、こんにちは整数です。

[]の出力

ライン全体的な最小の力値を表す整数。

[サンプル]入力

。3
。1. 1. 3

[出力]サンプル

4

[注]

[データサイズ]と表記

データN≤20の10%。

データN≤100の20%を。

データN≤5000の50%。

データ1≤N≤500000の100%に。

 

[説明]

 

動的計画。

 

放射線グループはたったの約2つの最後の段階で発見された、Fの定義[i] [j]は、最後の二つはプットが最小物理I、JのデフォルトI> Jでいた意味します

 

場合、J + 1、iは、I-1上に配置しなければならないI>、F [i]は[J] = F [I-1]〜[J] +スアン(I-1、I)。

 

当i=j+1时,则f[i][j]可以从f[i-1][k]  \(k \in  [1,i-1]\)转移。

 

发现下面的转移是O(n)的,期望得分50。

 

需要优化。

 

发现任意一个f[i][j](i>j+1)必是从f[j+1][j]处转移得到(一直放在第一个集合)。所以只需求出所有f[i-1][j]。

 

定义sum[i]表示从suan(1,2)+suan(2,3)+……+suan(i-1,i)。

 

f[i][i-1]=min(f[k][k-1]+sum[i-1]-sum[k]+suan(k-1,i))。

 

设g[i]=f[i][i-1],可以将suan里分类讨论分别求出-sum[k]+g[k]+h[k],和-sum[k]+g[k]-h[k]  按h值压入树状数组内维护前缀最小值即可快速求出从哪儿转移。

 

代码如下:

 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
map <int,int> dui;
int n,cnt=1,ls[N],a[N];
int g[N],sum[N],sh1[N],sh2[N],ans;
inline int read()
{
    char c=getchar();
    int x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return x;
}
inline int lowbit(int x)
{
    return x& (-x);
}
inline void update1(int x,int y)
{
    for(register int i=x;i<=cnt+1;i+=lowbit(i))
        sh1[i]=min(sh1[i],y);
}
inline void update2(int x,int y)
{
    for(register int i=x;i<=cnt+1;i+=lowbit(i))
        sh2[i]=min(sh2[i],y);
}
inline int query1(int x)
{
    int daan=100000000000000;
    for(register int i=x;i;i-=lowbit(i))
        daan=min(daan,sh1[i]);
    return daan;
}
inline int query2(int x)
{
    int daan=1000000000000;
    for(register int i=x;i;i-=lowbit(i))
        daan=min(daan,sh2[i]);
    return daan;
}
signed main()
{
    n=read();
    for(register int i=1;i<=n;i++)
    {
        a[i]=read();
        sum[i]=sum[i-1]+abs(a[i]-a[i-1]);
        ls[i]=a[i];
    }
    sort(ls+1,ls+n+1);
    for(register int i=1;i<=n;i++)
    {
        if(ls[i]!=ls[i-1]) 
        dui[ls[i]]=++cnt;
    }
    memset(sh1,63,sizeof(sh1));
    memset(sh2,63,sizeof(sh2));
    g[1]=a[1];ans=sum[n];
    update1(1,0);
    update2(cnt,0);
    for(register int i=2;i<=n;i++)
    {
        int hu1=query1(dui[a[i]]);
        int hu2=query2(cnt-dui[a[i]]+1);
        hu1+=a[i];hu2-=a[i];
        g[i]=min(hu1,hu2)+sum[i-1];
        ans=min(ans,g[i]+sum[n]-sum[i]);
        update1(dui[a[i-1]],g[i]-sum[i]-a[i-1]);
        update2(cnt-dui[a[i-1]]+1,g[i]-sum[i]+a[i-1]);
    }
    cout<<ans;
}
View Code

おすすめ

転載: www.cnblogs.com/betablewaloot/p/12173846.html