HYSBZ 1010 玩具装箱toy (决策单调DP)
?
題意:
有n個玩具,要將它們分為若干組,玩具長度C可能不同。給出n個玩具的擺放順序,連續的任意多個玩具都可以成為一組。區間[i,j]成為一組的費用是cost=(j-i+Sigma(Ck)-L)2且i<=k<=j。給定n和L和每個玩具的長度,問分組后費用總和是多少? (n<=5*104)。
?
?
思路:
轉移方程:dp[i]=min( dp[j]+(sum[i]-sum[j]+i-j+1-L)2 ?)。sum[i]表示前i件玩具長度的總和,0<j<i,(i-j+1)表示與i同組的玩具個數。
根據方程是可以推出這題是滿足決策單調性的。以下是抄來的證明,稍微修改:
令f[i]=sum[i]+i, c=1+L,則dp[i]=min( dp[j]+(f[i]-f[j]-c)2 ?)
1.證明決策單調性
假設在狀態i處的k決策優于j決策,且j<k,那么?dp[k]+(f[i]-f[k]-c)2<=dp[j]+(f[i]-dp[j]-c)2。
而對于i后面的某個狀態t,設f[t]=f[i]+v,先不管v是多少。
要證明:dp[k]+(f[t]-f[k]-c)2<=dp[j]+(f[t]-f[j]-c)2
只要證(將f[t]=f[i]+v代入):dp[k]+(f[i]+v-f[k]-c)2<=dp[j]+(f[i]+v-f[j]-c)2
只要證dp[k]+(f[i]-f[k]-c)2+2v*(f[i]-f[k]-c)+v2 ?<= ?dp[j]+(f[i]-f[j]-c)2+2v*(f[i]-f[j]-c)+v2。
由于假設,所以只要證:?2v*(f[i]-f[k]-c)<=2v*(f[i]-f[j]-c)。
即證:f[k]>=f[j](顯然)
證明完畢
?
?
思路很明確,一直卡在二分上面,噗。
用一個隊列來維護這些區間段,由于區間段必定是連在一起的,所以只需要記錄左端點L以及更新這個區間的決策k。如果隊列為空,則后面全部由i來更新得到,若非空,那么判斷隊尾的L,是否由i來更新會更優,若是,則pop掉隊尾,繼續同樣的動作,直到隊列為空或者i作為決策不如隊尾的L更好,那么i可以更新的就是[L,n]之中的尾部區間[r,n],而r可以用二分查找的方式。細節上很容易寫挫,比如i決策可能完全都可以用武之地,不用二分去找了,否則會錯;二分時必定要保證r由i來更新更佳,且有可能會出現等于的情況。復雜度O(nlogn),斜率優化等再寫。
?
?
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <set> 7 #include <deque> 8 #include <map> 9 #include <algorithm> 10 #include <vector> 11 #include <iostream> 12 #define pii pair<int,int> 13 #define back que[rear-1] 14 #define INF 0x7f7f7f7f 15 #define LL long long 16 #define ULL unsigned long long 17 using namespace std; 18 const double PI = acos(-1.0); 19 const int N=50100; 20 21 LL len[N], dp[N], L; 22 int q[N], d[N], n, l, r; //區間以及決策 23 LL cost(int j,int i) //用j來更新i的費用 24 { 25 return dp[j]+(len[i]-len[j]-L)*(len[i]-len[j]-L); 26 } 27 28 int find(int i,int k,int st) 29 { 30 int ll=st, rr=n; 31 while(ll<rr) 32 { 33 int mid=rr-(rr-ll+1)/2; 34 if( cost(i,mid)<cost(k,mid)) rr=mid; 35 else ll=mid+1; 36 } 37 return rr; 38 } 39 LL cal() 40 { 41 l=r=1; 42 d[1]=0;q[1]=1; //初始時,0可以更新[1,n] 43 for(int i=1; i<=n; i++) 44 { 45 dp[i]=cost(d[l], q[l]++); //q[l]永遠等于i 46 if( l<r && q[l]==q[l+1] ) l++; 47 48 while( l<=r && cost(i,q[r])<cost(d[r],q[r]) ) r--; 49 if(l>r) //只能用i來更新 50 { 51 q[++r]=i+1; 52 d[r]=i; 53 } 54 else if( cost(i,n)<cost(d[r],n)) 55 { 56 int tmp=find(i, d[r], q[r]); 57 q[++r]=tmp; 58 d[r]=i; 59 } 60 } 61 return dp[n]; 62 } 63 64 int main() 65 { 66 //freopen("input.txt","r",stdin); 67 while(~scanf("%d%lld",&n,&L)) 68 { 69 L++;len[0]=0; 70 for(int i=1; i<=n; i++) 71 { 72 scanf("%lld",&len[i]); 73 len[i]+=len[i-1]; 74 } 75 for(int i=1; i<=n; i++) len[i]+=i; 76 printf("%lld\n", cal() ); 77 } 78 return 0; 79 } AC代碼?
轉載于:https://www.cnblogs.com/xcw0754/p/4866121.html
總結
以上是生活随笔為你收集整理的HYSBZ 1010 玩具装箱toy (决策单调DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Eclipsephp工具打开Thin
- 下一篇: VS2015中DataGridView的