1. 程式人生 > >Cut the Sequence POJ

Cut the Sequence POJ

思路:dp[i]表示前第i項的最小值。

很容易寫出狀態轉移方程:dp[i]=min(dp[j]+max(a[j+1],a[i])),j<=i;

優化的思想是:我們需要快速的在前面找到一個j,同時還要找出j+1到i之間的最大項是什麼,這樣就能快速實現,最直接的思路是求RMQ,但是這題可以用單調佇列。

用單調佇列維護一個遞減的序列,對於當前的a[i],先將隊尾小於或等於a[i]的元素刪掉,再把a[i]插入隊尾。比如拿sample中的標號4-8一段8 1 8 2 1來看,那麼佇列裡面存的標號就是6 7 8,對應的a[]的值就是8 2 1。

其實我們可以發現,在第6項以後的最值就是佇列裡存的編號7,換句話說,我們列舉一個j,那麼下一個最值就是j+1對應的。

單調佇列中的下一個元素就是後一段的最大值。

最後還要保證任何區間的和不超過m,這個只要保證佇列的第一項到最後一項之和都不超過m,那麼列舉的任何子區間都不會超過m。

程式碼:

#include<iostream>  
#include<cmath>  
#include<cstdio>  
#include<cstdlib>  
#include<string>  
#include<cstring>  
#include<algorithm>  
#include<vector>  
#include<map>  
#include<set>  
#include<stack>  
#include<list>  
#include<queue>  
#include <deque>
const int maxn=1e5+9;
typedef long long ll;
ll n,m;
ll dp[maxn];
ll a[maxn];
struct node
{
    int index;
    ll val;
}que[maxn];
ll min(ll i,ll j)
{
    return i<j?i:j;
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        //sum[0]=0;
        bool f=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            if(a[i]>m) f=1;
            //sum[i]=sum[i-1]+a[i];
        }
        if(f==1)
        {
            printf("-1\n");
            continue;
        }
        int head,tail,pos;
        head=tail=0,pos=1;
        ll s=a[1];
        que[tail].val=dp[1]=a[1];
        que[tail++].index=1;
        for(int i=2;i<=n;i++)
        {
            s+=a[i];
            while(s>m&&pos<i)
            {
                s-=a[pos];
                pos++;
            }
            while(head<tail&&que[tail-1].val<=a[i])
            {
                tail--;
            }
            que[tail].val=a[i],que[tail++].index=i;
            while(que[head].index<pos&&head<tail)
            {
                head++;
            }
            dp[i]=dp[pos-1]+que[head].val;
            for(int j=head;j<tail-1;j++)
            {
                dp[i]=min(dp[i],dp[que[j].index]+que[j+1].val);
            }
        }
        printf("%lld\n",dp[n]);
    }
    return 0;
}