dp優化1——sgq(單調隊列)
該文是對dp的提高(並非是dp入門,dp入門者請先參考其他文章)
有時候dp的復雜度也有點大。。。會被卡。
這幾次blog大多數會講dp優化。
回歸noip2017PJT4.(題目可以自己去百度)。就是個很好的案例。那題是個二分套dp如果dp不優化復雜度O(n^2logn)還能拿60分(CCF太仁慈了,如果是我直接給10分)。
正解加上個單調隊列(其實是sliding window)O(nlogn)
我們發現,此類dp是這樣的
狀態i是由[l,r]轉移過來的。且i在向右移動的過程中,[l,r]一定會跟著往右移,那不就是單調隊列嗎!!!
至於單調隊列都不會的,我在這給一句解釋———如果一個人比你小,還比你強,那你就永遠比不過他了--chen_zhe大佬
其實是這樣的——能轉移到i的窗口[l,r]在向右移動的過程中,我們加一個隊列,隊首的dp值最優,在r向右移動時,遇到一個狀態t
寫個偽代碼
while(隊列不空&&t的dp值由於隊尾值)彈出隊尾元素;將t插入隊尾
別忘了,l還要向右移動,右移會導致一些狀態離開隊列,需要在原隊列刪除。
OK接下來看例題:
多重背包n個物體,每個numi個,每個物品右價值和重量,求重量不超過m的最大價值(不會o(n^2m)請自行百度,改文不介紹過於基礎的dp)。
您會說一句,這種水題我30s切。結果切完後就30分。。。。
一拍腦袋,二進制優化-》O(nmlogn)(將numi分解二進制,再用01做)
結果毒瘤的數據結構大師lxl成功卡掉了您的log(送你《涼涼》x1)
看來只能用O(nm)的做法,先寫下dp轉移方程
dp[i][j]表示前i個物體,限制重量為j的最大價值
dp[i][j]=max(dp[i-1][j-k*w[i]]+v[i]*k)(0<=k<=num[i])
狀壓:dp[j]=max(dp[j-k*w[i]]+v[i]*k)
我們先瞎搞:
在i和j都確定的情況下:
設:
n*w[i]+p=j p=j%w[i];
j/w[i]=n(註意是整除)
原方程變為dp[j]=max(dp[j%w[i]+k*w[i]]-k*w[i])+n*w[i](2)
聰明的你一定會了。
這個方程的k與原來的K不同(為區分下文將原來的K大寫)
如果你自己推過(2),您會發現k=n-K
這樣可以搞出k的範圍
0<=n-k<=num[i]
n-num[i]<=k<=n
在j%w【i】不變時max(dp[j%w[i]+k*w[i]]-k*w[i])只與k有關,爽歪歪~~ 單調隊列嘍。
不懂再想想這張圖(important)
沒例題總不行!!例題是hdu1171(多重背包裸題)。但出題者非常善良,O(n^2m)也給過了。
單調隊列79MS,純dp1092MS
代碼:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int dp[2][250011],v[500011],num[500011]; int q[10000000],l,r,n; int main(){//freopen("in.txt","r",stdin);freopen("o1.txt","w",stdout); while(scanf("%d",&n)!=EOF && n>=0){ memset(dp,0,sizeof(dp));memset(v,0,sizeof(v));memset(num,0,sizeof(num)); l=r=0; int i,sum=0,j; for(i=1;i<=n;++i)scanf("%d%d",&v[i],&num[i]),sum+=v[i]*num[i]; int m=sum>>1,p,ans=0; for(i=1;i<=n;++i){ for(p=0;p<v[i];++p){ int kl,kr; l=r=0;l=1;q[++r]=0; for(j=p;j<=m;j+=v[i]){ int pre=kr; kl=max(j/v[i]-num[i],0),kr=j/v[i]; while(l<=r && (q[l]<kl || q[l]>kr))++l; for(int k=pre+1;k<=kr;++k){ while(l<=r && dp[i%2^1][j%v[i]+q[r]*v[i]]-q[r]*v[i]<dp[i%2^1][j%v[i]+k*v[i]]-k*v[i])--r; q[++r]=k; } dp[i%2][j]=dp[i%2^1][j%v[i]+q[l]*v[i]]-q[l]*v[i]+(j/v[i])*v[i]; ans=max(ans,dp[i%2][j]); } } } printf("%d %d\n",sum-ans,ans); } }
dp優化1——sgq(單調隊列)