题目概述
给出一个有权值的矩阵,一次操作将这个矩阵沿着行或列切成两半,然后这两半也可以执行同样的操作。操作 n−1 n − 1 次后得到 n n 个矩阵,求这 个矩阵的均方差(标准差?傻傻分不清啊QAQ)。
解题报告
五维DP f[i][j][x][y][k] f [ i ] [ j ] [ x ] [ y ] [ k ] 表示将矩阵 i i 行到 行 j j 列到 列执行 k−1 k − 1 次操作得到的最优解,转移的话就直接枚举在哪里切开,两边分别执行多少次操作。用记忆化搜索来写比较方便。
示例程序
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=10,maxk=10;
int n,m,K;LL f[maxn+5][maxn+5][maxn+5][maxn+5][maxk+5];
int all,sum[maxn+5][maxn+5];
inline LL sqr(LL x) {return x*x;}
#define val(i,j,x,y) sqr(sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1]-all)
inline LL DP(int i,int j,int x,int y,int k){
if (k==1) return val(i,j,x,y);if ((x-i+1)*(y-j+1)<k) return 1e18;
LL &now=f[i][j][x][y][k];if (~now) return now;now=1e18;
for (int p=i;p<x;p++) for (int t=1;t<k;t++) now=min(now,DP(i,j,p,y,t)+DP(p+1,j,x,y,k-t));
for (int p=j;p<y;p++) for (int t=1;t<k;t++) now=min(now,DP(i,j,x,p,t)+DP(i,p+1,x,y,k-t));
return now;
}
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);memset(f,255,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
scanf("%d",&sum[i][j]);all+=sum[i][j];
sum[i][j]*=K;sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
return printf("%.2f\n",sqrt((double)DP(1,1,n,m,K)/K/K/K)),0;
}