题目传送门
题意: 给你一个棋盘,你每次可以对棋盘剩余部分砍一刀,并且要保证砍完后的剩余部分还是矩形。现在我们要用这种规则将这块棋盘砍成n份,每一份的分值就是这一块内每个小方格代表数字的和,现在我们要你求出这n份的最小的均方差(标准差)。
思路: 我们可以推算出 σ 2 = 1 / n ∑ x i 2 − x ′ 2 ( x ′ 表 示 平 均 数 ) σ^2=1/n\sum x_i^2-x'^2(x'表示平均数) σ2=1/n∑xi2−x′2(x′表示平均数),然后我们可以用 f [ k ] [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] f[k][x1][y1][x2][y2] f[k][x1][y1][x2][y2]表示以 ( x 1 , y 1 ) (x1,y1) (x1,y1)为左上角, ( x 2 , y 2 ) (x2,y2) (x2,y2)为右下角的矩形,砍k次,能获得的最小 ∑ x i 2 \sum x_i^2 ∑xi2,然后直接枚举每一个矩形,我们有两种转移方式:横着切和竖着切,每次切出来的两块你要考虑哪一块继续砍,即砍k-1次。最后按照公式计算输出即可。
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
//#define int long long
#define pii pair<int,int>
#define ull unsigned long long
#define pdd pair<double,double>
#define lowbit(x) x&-x
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
int x=0,f=1;
char ch=gc();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=gc();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=gc();
}
return x*f;
}
using namespace std;
const int N=2e5+55;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-6;
const double PI=acos(-1);
int a[10][10],sum[10][10],f[20][10][10][10][10];
void dfs(int k,int x1,int y1,int x2,int y2)
{
f[k][x1][y1][x2][y2]=inf;
for(int i=x1;i<x2;i++)
{
f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],f[k-1][x1][y1][i][y2]+f[0][i+1][y1][x2][y2]);
f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],f[0][x1][y1][i][y2]+f[k-1][i+1][y1][x2][y2]);
}
for(int i=y1;i<y2;i++)
{
f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],f[k-1][x1][y1][x2][i]+f[0][x1][i+1][x2][y2]);
f[k][x1][y1][x2][y2]=min(f[k][x1][y1][x2][y2],f[0][x1][y1][x2][i]+f[k-1][x1][i+1][x2][y2]);
}
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=8;i++)
{
for(int j=1;j<=8;j++)
{
cin>>a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
for(int i=1;i<=8;i++)
{
for(int j=1;j<=8;j++)
{
for(int p=i;p<=8;p++)
{
for(int q=j;q<=8;q++)
{
int t=sum[p][q]-sum[p][j-1]-sum[i-1][q]+sum[i-1][j-1];
f[0][i][j][p][q]=t*t;
}
}
}
}
for(int k=1;k<=n-1;k++)
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
for(int p=i;p<=8;p++)
for(int q=j;q<=8;q++)
dfs(k,i,j,p,q);
int tot=f[n-1][1][1][8][8];
double avy=sum[8][8]*1.0/n;
double ans=sqrt(1.0*tot/n-avy*avy);
printf("%.3f\n",ans);
}
signed main()
{
solve();
return 0;
}