1. 程式人生 > >codeforces 1101F Trucks and Cities 區間dp+單調優化 好題

codeforces 1101F Trucks and Cities 區間dp+單調優化 好題

mem 所有 大於 www. 最大值 取值 之間 發現 contest

題目傳送門

題意簡述:(來自洛谷)

n個城市坐落在一條數軸上,第ii個城市位於位置ai?

城市之間有m輛卡車穿行.每輛卡車有四個參數:si?為起點編號,fi?為終點編號,ci?表示每行駛1個單位長度需要消耗的油量,ri?表示可以在路途中加油的次數.

當卡車到達一個城市的時候可以將油加滿(當然也可以不加),在路中無法加油,但是路途中總加油次數不能超過ri?

所有卡車的油箱都是一樣大的,我們稱它的容積為V.試求一個最小的V,使得對於所有的卡車都存在一種方案,在路途中任意時刻油箱內的油量大於等於0且路途中總加油次數小於等於ri?的情況下從起點城市到達終點城市.

n,m(n400,m250000)表示城市數量與卡車數量。

思路:

  此題學習了洛谷的博客,但洛谷的博客有地方是錯誤的,導致自閉了許久,自己證明了一波,才走出自閉。

  洛谷題解 點這裏 但是洛谷題解有錯,並且最重要的單調性沒有證明。

  首先,主體是一個區間DP

  設 dp{i,j,k}? 為:從第 i 個城市到第 j 個城市分成 k 段,這 k 段中長度最大的一段的最小值

  邊界: dp{i,j,0}=aj-ai(1≤i≤j≤n)。

  狀態轉移方程

  dp {i,j,k}=dp{i,j,k}?=min? (max(dp{i,w,k?1}?,aj??aw?))(0<kn))( i <= w <= j )

  目標:max?(ci*?dp{si?,fi?,ri?}?) i<=m

以上均取自洛谷,並且洛谷的狀態轉移方程還寫錯了。上面這個區間dp的時間復雜度是O(n4)的,顯然會超時,要進行優化,洛谷題解中說單調性是顯然得出的,,然而我證明了好久。

先說兩個結果:

  1)當 k,i 確定, j 在不斷向右移時,對每個 j 取到的 w 具有單調性。

  2)同時,當 j 確定時,不同的 w 對應的取值呈“先減後增” 的趨勢,

  我們先證明第二點,當i j k 確定時,轉移方程中 我們設dp{i,w,k?1}?為 Aw,aj??aw? 為Bw,當w變大時,Aw可能變大,Bw必定變小,所以取值一開始肯定是取Bw的,慢慢變的有可能取Aw,可以想象,這個dp方程一開始肯定是w越大越好,但是當某一個臨界點,如果比前面大了,那我們會發現,此時的最大值必定不是Bw,因為Bw<B(w-1),這是必定的。所以最大值是Aw,而w越大,Aw則可能變大,但絕不變小,所以不會有變小的趨勢了,證畢。

  然後證明第一點,假設j‘=j+1,我們先看w是否會前移。發現j變成j‘後,只有Bw會變大,Aw是不變的,而越往後的項,最大值取Aw的可能性越大,所以前面的項只會變大,就算當前項變大了,那變大的程度也會和前面的一樣,所以取最小值的話當前w必定由於小於w的值。

  那麽看w是否會後移,由於Bw會變大,Aw只是可能變大,後面的項比前面的項更有可能用到Aw,所以後面的項可能更優,w可能後移,有單調性,證畢。

  註意不要開數組不要long long,會爆內存,也不要開太大,開了410*410*410會mle。

技術分享圖片
#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=402;
ll ans;
int dp[maxn][maxn][maxn],a[maxn];
int n,m;
int main(){
    while(cin>>n>>m)
    {
        ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                dp[i][j][0]=a[j]-a[i];
            }
        }
        for(int k=1;k<=n;k++)
        {
            for(int i=1;i<=n;i++)
            {
                int w=i;
                for(int j=i;j<=n;j++)
                {
                    while(w<j&&max(dp[i][w][k-1],a[j]-a[w])>max(dp[i][w+1][k-1],a[j]-a[w+1]))w++;
                    dp[i][j][k]=max(dp[i][w][k-1],a[j]-a[w]);
                }
            }
        }
        int s,f,r;
        ll c;
        while(m--)
        {
            scanf("%d%d%lld%d",&s,&f,&c,&r);
            ans=max(ans,dp[s][f][r]*c);
        }
        cout<<ans<<endl;
    }
} 
View Code

codeforces 1101F Trucks and Cities 區間dp+單調優化 好題