题意是你有一个长为n的01串,定义一个01串的值为其中0的个数和1的个数的乘积
要求把这个01串分为k段,使得这k段的值的和最小
------------------------题意结束的分割线------只看题意的可以回了-----------
定义状态dp[i][j]为前j个字符分为i段的最小的值
cal(l,r)是从l到r的值
dp方程为dp[i][j]=min(dp[i][j],dp[i-1][l]+cal(l+1,j));
cal可以事先预处理出来降低复杂度
代码如下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=600;
int arr[maxn];
int o[maxn];
int z[maxn];
void calall(int n){
memset(o,0,sizeof(o));
memset(z,0,sizeof(z));
for(int i=1;i<=n;i++){
o[i]=o[i-1];
z[i]=z[i-1];
if(arr[i]==1)
o[i]++;
else
z[i]++;
}
}
int cal(int l,int r){
return (o[r]-o[l-1])*(z[r]-z[l-1]);
}
int dp[maxn][maxn];
int main(){
int n,k;
memset(arr,-1,sizeof(arr));
while(~scanf("%d %d",&n,&k)){
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
calall(n);
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<=k;i++)
dp[i][0]=0;
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
for(int l=0;l<j;l++)
dp[i][j]=min(dp[i][j],dp[i-1][l]+cal(l+1,j));
// for(int i=0;i<=k;i++)
// for(int j=0;j<=n;j++)
// printf(j<n?"%d ":"%d\n",dp[i][j]);
printf("%d\n",dp[k][n]);
}
return 0;
}
cal可以事先预处理出来降低复杂度