题面:
思路:
因为集合可以无序选择,所以我们先把输入数据排个序
然后发先可以动归一波
设$dpleft[i ight]left[j ight]$表示前j个数中分了i个集合,$wleft(i ight)left(j ight)$表示$i$到$j$的闭区间分到一个集合里的花费
然后就有方程式:
$dpleft[i ight]left[j ight]=minleft(dpleft[i-1 ight]left[k-1 ight]+wleft(k ight)left(j ight) ight)$
可是这道题$n=10000,m=5000$,目测这样跑区间$dp$时间复杂度依然很捉急啊
没关系,我们请出四边形不等式优化
容易证明,$w$函数满足四边形不等式,同时满足区间单调性
因此$dp$函数也满足四边形不等式,可以优化
优化完以后是$Oleft(nm ight)$的效率,AC~
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 unsigned int inf=0x7fffffff; 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[10010]; 17 unsigned int dp[5010][10010];short s[5010][10010]; 18 unsigned int w(int l,int r){ 19 return (a[l]-a[r])*(a[l]-a[r]); 20 } 21 int main(){ 22 int i,j,k,len,T=read(),cnt=0;unsigned tmp; 23 while(T--){ 24 n=read();m=read(); 25 for(i=1;i<=n;i++) a[i]=read(); 26 sort(a+1,a+n+1); 27 for(i=0;i<=m;i++) dp[i][i]=0,s[i][i]=i; 28 for(i=m+1;i<=n;i++) s[m+1][i]=i; 29 for(len=1;len<n;len++){ 30 dp[0][len]=inf; 31 for(i=1;i<=m;i++){ 32 j=i+len;if(j>n) break; 33 dp[i][j]=inf; 34 for(k=s[i][j-1];k<=s[i+1][j];k++){ 35 if((tmp=dp[i-1][k-1]+w(k,j))<dp[i][j]){ 36 dp[i][j]=tmp;s[i][j]=k; 37 } 38 } 39 } 40 } 41 printf("Case %d: %d ",++cnt,dp[m][n]); 42 } 43 }