这题是一道区间DP
思维难度主要集中在如何预处理距离上
由生活经验得,邮局放在中间显然最优
所以我们可以递推求出( w[i][j] )表示i,j之间放一个邮局得距离
然后设出状态转移方程
设( dp[i][j] )表示从1开始到i放j个邮局的最短距离
然后转移为:( dp[i][j]=min(dp[k][j-1]+w[k+1][j],dp[i][j]),i le k le j )
显然是个( O(n^{3}) )的DP
能够得40分
#include <cstdio> #include <algorithm> #include <cstring> #define int long long using namespace std; int w[3010][3010],dp[3010][310],n,p,x[3010]; signed main(){ scanf("%lld %lld",&n,&p); for(int i=1;i<=n;i++) scanf("%lld",&x[i]); sort(x+1,x+n+1); memset(w,0x3f,sizeof(w)); for(int i=1;i<=n;i++) w[i][i]=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) w[i][j]=w[i][j-1]+x[j]-x[(i+j)/2]; memset(dp,0x3f,sizeof(dp)); for(int i=1;i<=n;i++) dp[i][1]=w[1][i]; for(int i=1;i<=p;i++) dp[i][i]=0; for(int i=2;i<=p;i++) for(int j=i+1;j<=n;j++) for(int k=i-1;k<=j;k++){ dp[j][i]=min(dp[j][i],dp[k][i-1]+w[k+1][j]); //5 printf("%d %d %d %d ",i,j,k,dp[j][i]); } /*for(int l=1;l<=n;l++) for(int i=1;i+l<=n;++) printf("w[%d][%d]=%d ",i,i+l,w[i][i+l]);*/ printf("%lld ",dp[n][p]); return 0; }
然后就是优化
我们可以发现一些显然的性质
( w[i^{'}][j] le w[i][j^{'}] , i le i^{'} le j le j^{'} )
( w[i][j]+w[i^{'}][j^{'}] le w[i^{'}][j]+w[i][j^{'}] )
然后就可以用四边形不等式优化DP了!
然后QwQ
复杂度( O(n^{2}) )
没了
#include <cstdio> #include <algorithm> #include <cstring> #define int long long using namespace std; int w[3010][3010],dp[3010][310],n,p,x[3010],s[3010][310]; signed main(){ scanf("%lld %lld",&n,&p); for(int i=1;i<=n;i++) scanf("%lld",&x[i]); sort(x+1,x+n+1); memset(w,0x3f,sizeof(w)); for(int i=1;i<=n;i++) w[i][i]=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) w[i][j]=w[i][j-1]+x[j]-x[(i+j)/2]; memset(dp,0x3f,sizeof(dp)); for(int i=1;i<=n;i++) dp[i][1]=w[1][i],s[i][1]=0;; for(int i=1;i<=p;i++) dp[i][i]=0; for(int i=2;i<=p;i++){ s[n+1][i]=n; for(int j=n;j>=i+1;j--) for(int k=s[j][i-1];k<=s[j+1][i];k++) if(dp[j][i]>dp[k][i-1]+w[k+1][j]){ dp[j][i]=dp[k][i-1]+w[k+1][j]; s[j][i]=k; //5 printf("%d %d %d %d ",i,j,k,dp[j][i]); } } /*for(int l=1;l<=n;l++) for(int i=1;i+l<=n;++) printf("w[%d][%d]=%d ",i,i+l,w[i][i+l]);*/ printf("%lld ",dp[n][p]); return 0; }