維護一段連續區間的極值並且快速取出 用雙端佇列維護單調的序列
下面來到例題目
最近lxhgww又迷上了投資**,通過一段時間的觀察和學習,他總結出了****的一些規律。
通過一段時間的觀察,lxhgww**到了未來t天內某只**的走勢,第i天的****價為每股api,第i天的**賣出價為每股bpi(資料保證對於每個i,都有api>=bpi),但是每天不能無限制地交易,於是**交易所規定第i天的一次**至多只能購買asi股,一次賣出至多只能賣出bsi股。
另外,**交易所還制定了兩個規定。為了避免大家瘋狂交易,**交易所規定在兩次交易(某一天的**或者賣出均算是一次交易)之間,至少要間隔w天,也就是說如果在第i天發生了交易,那麼從第i+1天到第i+w天,均不能發生交易。同時,為了避免壟斷,**交易所還規定在任何時間,乙個人的手裡的**數不能超過maxp。
在第1天之前,lxhgww手裡有一大筆錢(可以認為錢的數目無限),但是沒有任何**,當然,t天以後,lxhgww想要賺到最多的錢,聰明的程式設計師們,你們能幫助他嗎?
解:揹包問題
定義f[i][j]表示i天持有j** 所獲得的最大收益 第i天不一定要買
所以方程轉移為
\(f[i][j]=max(f[i-w-1][k]+(k-j)*b,f[i-w-1][k]-(j-k)*a,f[i-1][j]);\)
然後提取常數
注意到k的範圍為$ [j,j+b[i]] 和[j-a[i],j];$
滿足一段區間求極大極小值
所以就可以利用單調佇列進行優化
為甚們是i-w-1 ? 而不是前面的數
因為我們定義的時候i-w-1 並不是一定要買 所以是前面的最優狀態
至於初始值怎麼賦?
除了f[0][0] 的狀態都賦值為-inf
其餘的每次取到能買的上限 具體看**
code:
//
#includeusing namespace std;
#define maxnn 3000
#define ll long long
ll t,p,w;
ll f[maxnn][maxnn];
ll a1[maxnn],a2[maxnn],b1[maxnn],b2[maxnn];
dequeq;
int main()
for(int i=0; i<=t; i++)for(int j=0; j<=p; j++)f[i][j]=-2333333;
f[0][0]=0;
for(int i=1; i<=t; i++)
while(index<=min(p,b2[i]+j))
q.push_back(index);
index++;
} f[i][j]=max(f[i][j],f[i-w-1][q.front()]+b1[i]*(q.front())-j*b1[i]);
} index=0;
q.clear();
q.push_back(index);
for(ll j=0;j<=p;j++)
while(index<=min(p,j))
q.push_back(index);
index++;
} f[i][j]=max(f[i][j],f[i-w-1][q.front()]+a1[i]*(q.front())-j*a1[i]);
} }
ll ans=-111110;
for(int i=0;i<=p;i++)
cout<}
單調佇列 優化DP
佇列元素保持單調遞增 減 而保持的方式就是通過插隊,把隊尾破壞了單調性的數全部擠掉,從而使佇列元素保持單調。單調佇列的作用 優化dp。許多單調佇列優化的dp可以使複雜度直接降維,下面就以最簡單的一道題為例 在某兩座城市之間有 n 個烽火台,每個烽火台發出訊號都有一定代價。為了使情報準確地傳遞,在連續...
單調佇列優化dp
形如f i max wi的問題都可以用單調佇列優化。例題 板題 注意乙個地方 求完所有的f後 ans不是f n 而是後面的一段字尾的f 注意字尾的左端點。很顯然是rmq問題 計算字首和sum i 對於固定的右端點 i,我們想讓答案最大等價於max,可以用個單調佇列維護。但是隨便乙個資料結構直接on ...
DP 單調佇列優化
使用單調佇列優化的題目具有這樣的特點,他需要我們維持一段區間內的某個最優值,這個區間是隨著遍歷的順序變化的,但是其變化一定具有這樣的特性,也即維持的區間左右端點一定是單調遞增的,而不能出現回流的現象,否則我們在維持佇列單調性過程中剪枝的資料可能是新的區間中的最大值。維持區間最優值的方法有很多,例如靜...