_(:3」∠)_
dp[i][j]:前i个分j组的最小值
cost[i][j]:i到j为一组的值
sum[i]:前i个的值的总和
dp[i][j]=min{dp[k][j-1]+cost[k+1][i]}
cost[k+1][i]=cost[1][i]-cost[1][k]-sum[k]*(sum[i]-sum[k])=cost[i]-cost[k]+sum[k]*sum[k]-sum[k]*sum[i]
令y=dp[k][j-1]-cost[k]+sum[k]*sum[k]
则dp[i][j]=min{y+cost[i]-sum[k]*sum[i]}
sum[i]为斜率
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<iostream> 6 #include<queue> 7 #include<stack> 8 #include<cmath> 9 #include<map> 10 #define BUG printf("hehe ") 11 #define INF 0x3f3f3f3f 12 #define ll long long 13 using namespace std; 14 15 int cost[1010],sum[1010]; 16 int dp[1010][1010],q[1010]; 17 int n,m,head,tail; 18 19 int dx(int a,int b) 20 { 21 return sum[a]-sum[b]; 22 } 23 24 int dy(int x,int a,int b) 25 { 26 return dp[a][x]-cost[a]+sum[a]*sum[a]-(dp[b][x]-cost[b]+sum[b]*sum[b]); 27 } 28 29 int main() 30 { 31 int t; 32 while(scanf("%d%d",&n,&m)&&(n|m)) { 33 sum[0]=0; 34 cost[0]=0; 35 for(int i=1;i<=n;++i) { 36 scanf("%d",&t); 37 sum[i]=sum[i-1]+t; 38 cost[i]=cost[i-1]+t*sum[i-1]; 39 } 40 for(int i=1;i<=n;++i) 41 dp[i][1]=cost[i]; 42 43 for(int j=2;j<=m+1;++j) { 44 head=0,tail=-1; 45 q[++tail]=j-1; 46 for(int i=j;i<=n;++i) { 47 while(head<tail&&(dy(j-1,q[head+1],q[head])<sum[i]*dx(q[head+1],q[head]))) ++head; 48 dp[i][j]=dp[q[head]][j-1]-cost[q[head]]+sum[q[head]]*sum[q[head]]+ 49 cost[i]-sum[i]*sum[q[head]]; 50 while(head<tail&&(dy(j-1,i,q[tail])*dx(q[tail],q[tail-1]) 51 <=dy(j-1,q[tail],q[tail-1])*dx(i,q[tail]))) --tail; 52 q[++tail]=i; 53 } 54 } 55 printf("%d ",dp[n][m+1]); 56 } 57 }
四边形优化:
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<iostream> #include<queue> #include<stack> #include<cmath> #include<map> #define BUG printf("hehe ") #define INF 0x3f3f3f3f #define ll long long using namespace std; int cost[1010][1010],sum[1010]; int s[1010][1010]; int dp[1010][1010]; int a[1010]; int n,m,head,tail; int main() { int n,m; while(scanf("%d%d",&n,&m)&&(n|m)) { sum[0]=0; for(int i=1;i<=n;++i) { scanf("%d",a+i); sum[i]=sum[i-1]+a[i]; } memset(cost,0,sizeof cost); for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) { cost[i][j]=cost[i][j-1]+a[j]*(sum[j-1]-sum[i-1]); } for(int i=0;i<=n;++i) { dp[i][1]=cost[1][i]; s[i][1]=1; s[n+1][i]=n-1; } for(int j=2;j<=m+1;++j) { for(int i=n;i>=1;--i) { dp[i][j]=INF; for(int k=s[i][j-1];k<=s[i+1][j];++k) { if(dp[k][j-1]+cost[k+1][i]<dp[i][j]) { s[i][j]=k; dp[i][j]=dp[k][j-1]+cost[k+1][i]; } } } } printf("%d ",dp[n][m+1]); } }