BZOJXXXX: [IOI2000]邮局——四边形不等式优化初探
貌似$BZOJ$上并沒有這個題。。。
是嫌這個題水了么。。。
還是要氪金權限號???
這里附上洛谷的題面:洛谷P4767 [IOI2000]郵局
題目描述
高速公路旁邊有一些村莊。高速公路表示為整數軸,每個村莊的位置用單個整數坐標標識。沒有兩個在同樣地方的村莊。兩個位置之間的距離是其整數坐標差的絕對值。
郵局將建在一些,但不一定是所有的村莊中。為了建立郵局,應選擇他們建造的位置,使每個村莊與其最近的郵局之間的距離總和最小。
你要編寫一個程序,已知村莊的位置和郵局的數量,計算每個村莊和最近的郵局之間所有距離的最小可能的總和。
輸入輸出格式
輸入格式:
?
第一行包含兩個整數:第一個是村莊$V$的數量,第二個是郵局的數量$P$,$1 \leq P \leq 300$,$P \leq V \leq 3000$.
第二行包含$V$個整數。這些整數是村莊的位置。對于每個位置$X$,認為$1 \leq X \leq 10000$。
?
輸出格式:
?
第一行包含一個整數$S$,它是每個村莊與其最近的郵局之間的所有距離的總和。
?
輸入輸出樣例
輸入樣例#1:?復制 10 5 1 2 3 6 7 9 11 22 44 50 輸出樣例#1:?復制 9說明
對于40%的數據,$V \leq 300$
題解Here!
首先這是個區間$DP$對吧。
我們一步一步來分析:
首先要將村莊位置排個序,不用多說。
下面開始$DP$。
$No. 1:\text{普通DP}$:
設$dp[i][j]$表示前$i$個村莊中建了$j$個郵局的最優方案。
轉移方程長這個樣:
$$dp[i][j]=\max\{\ dp[k][j-1]+dis(k+1,i)\ |\ k\in[0,i)\}$$
其中$dis(l,r)$表示在$[l,r]$這個區間內的村莊中建一個郵局對答案的貢獻。
利用人類智慧可知把郵局建在中間花費最少。。。
復雜度上限是$O(n^3m)$,實測可以$40\text{分}$。
代碼如下:
inline int abs(int x){return x>0?x:-x;} inline int dis(int l,int r){int mid=(l+r)>>1,s=0;for(int i=l;i<=r;i++)s+=abs(pos[i]-pos[mid]);//pos是村莊位置return s; } void work(){dp[0][0]=0;for(int i=1;i<=n;i++)for(int j=1;j<=m&&j<=i;j++)for(int k=0;k<i;k++)dp[i][j]=min(dp[i][j],dp[k][j-1]+dis(k+1,i));printf("%d\n",dp[n][m]); }$No. 2:\text{普通DP+優化}$:
我們發現我們的求貢獻還要$O(n)$的復雜度,考慮對其進行優化。
我們知道:
$$dis(l,r)=\sum_{i=l}^r|pos_i-pos_{mid}|,mid=\frac{l+r}{2}$$
因為我們的$pos$是有序的,于是:
$$dis(l,r)=\sum_{i=l}^{mid-1}(pos_{mid}-pos_i)+\sum_{i=mid+1}^r(pos_i-pos_{mid}),mid=\frac{l+r}{2}$$
顯然拆開:
$$dis(l,r)=(mid-l)pos_{mid}-\sum_{i=l}^{mid-1}pos_i+\sum_{i=mid+1}^rpos_i-(r-mid)pos_{mid},mid=\frac{l+r}{2}$$
合并:
$$dis(l,r)=(2mid-l-r)pos_{mid}+\sum_{i=mid+1}^rpos_i-\sum_{i=l}^{mid-1}pos_i,mid=\frac{l+r}{2}$$
注意,這個地方$2mid-l-r \neq 0$,因為實際算$mid$時,算的其實是$\lfloor\frac{l+r}{2}\rfloor$。
但是這個并不影響復雜度,所以可以保留。
關鍵是后面那兩個$\sum$怎么整?
前綴和!
設$sum(x)=\sum_{i=1}^xpos_i$,則:
$$\left.\begin{array}{}dis(l,r)&=&(2mid-l-r)pos_{mid}+(sum(r)-sum(mid))-(sum(mid-1)-sum(l-1))\\&=&(2mid-l-r)pos_{mid}+sum(l-1)+sum(r)-sum(mid)-sum(mid-1)\end{array}\right.$$
于是預處理前綴和,就可以$O(1)$計算$dis(l,r)$了!
復雜度$O(n^2m)$,實測$60\text{分}$。
代碼如下:
inline int dis(int l,int r){int mid=(l+r)>>1;return ((sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])+(mid*2-l-r)*pos[mid]); } void work(){dp[0][0]=0;for(int i=1;i<=n;i++)for(int j=1;j<=m&&j<=i;j++)for(int k=0;k<i;k++)dp[i][j]=min(dp[i][j],dp[k][j-1]+dis(k+1,i));printf("%d\n",dp[n][m]); }$No. 3:\text{DP+四邊形不等式}$:
四邊形不等式優化就是:
在$DP$過程中滿足:
$$dp[a][c]+dp[b][d]<=dp[a][d]+dp[b][c]$$
并且決策具有單調性。
對于這題,我們發現,$dp[i][j]$的決策只能從$dp[i][j-1],dp[i+1][j]$中選一個進行轉移。
于是就可以用四邊形不等式優化了!
到此,我們證明了這個題其實是個板子題。。。
記得要倒序$DP$。
附代碼:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 3010 using namespace std; int n,m; int pos[MAXN],sum[MAXN],from[MAXN][MAXN],dp[MAXN][MAXN]; inline int read(){int date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w; } inline int dis(int l,int r){int mid=(l+r)>>1;return ((sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])+(mid*2-l-r)*pos[mid]); } void work(){for(int j=2;j<=m;j++){from[n+1][j]=n;for(int i=n;i>=1;i--){for(int k=from[i][j-1];k<=from[i+1][j];k++){if(dp[k][j-1]+dis(k+1,i)<dp[i][j]){dp[i][j]=dp[k][j-1]+dis(k+1,i);from[i][j]=k;}}}}printf("%d\n",dp[n][m]); } void init(){n=read();m=read();memset(dp,127,sizeof(dp));for(int i=1;i<=n;i++)pos[i]=read();sort(pos+1,pos+n+1);sum[0]=0;for(int i=1;i<=n;i++){sum[i]=sum[i-1]+pos[i];dp[i][1]=dis(1,i);} } int main(){init();work();return 0; }?
轉載于:https://www.cnblogs.com/Yangrui-Blog/p/9862813.html
總結
以上是生活随笔為你收集整理的BZOJXXXX: [IOI2000]邮局——四边形不等式优化初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql中group by 的用法解析
- 下一篇: [九省联考2018]IIIDX 贪心 线