题面:
思路:
dp方程实际上很好想
设$dpleft[i ight]left[j ight]$表示前$j$个镇子设立$i$个邮局的最小花费
然后状态转移:
$dpleft[i ight]left[j ight]=minleft(dpleft[i-1 ight]left[k-1 ight]+wleft(k,j ight) ight)$
其中$w$表示在这个闭区间内设立一个邮局的最小费用
推一下发现这里$w$可以$Oleft(1 ight)$前缀和计算,或者$Oleft(n^2 ight)$预处理
本来到这里这道题目其实就解决了(因为$n$只有$300$)
但是我们本着优化到底的精神,来重新审视这个方程,结果发现:
这不就是四边形不等式第二类情形吗!
然后证明一下$w$的四边形不等式,然后优化,变成$Oleft(n^2 ight)$
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define inf 1e9 6 using namespace std; 7 inline int read(){ 8 int re=0,flag=1;char ch=getchar(); 9 while(ch>'9'||ch<'0'){ 10 if(ch=='-') flag=-1; 11 ch=getchar(); 12 } 13 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 14 return re*flag; 15 } 16 int n,m,a[310],sum[310]; 17 int dp[310][310],s[310][310]; 18 int w(int l,int r){ 19 int t=(l+r)>>1; 20 return (sum[r]-sum[t])-(sum[t-1]-sum[l-1])-(r-t)*a[t]+(t-l)*a[t]; 21 } 22 int main(){ 23 int i,j,p,k,tmp; 24 n=read();m=read(); 25 for(i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i]; 26 for(i=0;i<=n;i++) dp[i][i]=0,s[i][i]=i; 27 for(p=1;p<=n-m;p++){ 28 dp[0][p]=inf; 29 for(i=1;(j=i+p)<=n;i++){ 30 dp[i][j]=inf; 31 for(k=s[i][j-1];k<=s[i+1][j];k++){ 32 if((tmp=dp[i-1][k-1]+w(k,j))<dp[i][j]){ 33 dp[i][j]=tmp;s[i][j]=k; 34 } 35 } 36 } 37 } 38 printf("%d ",dp[m][n]); 39 }