AcWing 321. 棋盘分割(区间dp)

题目传送门

题意: 给你一个棋盘,你每次可以对棋盘剩余部分砍一刀,并且要保证砍完后的剩余部分还是矩形。现在我们要用这种规则将这块棋盘砍成n份,每一份的分值就是这一块内每个小方格代表数字的和,现在我们要你求出这n份的最小的均方差(标准差)。

思路: 我们可以推算出 σ 2 = 1 / n ∑ x i 2 − x ′ 2 ( x ′ 表 示 平 均 数 ) σ^2=1/n\sum x_i^2-x'^2(x'表示平均数) σ2=1/nxi2x2(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;
}

猜你喜欢

转载自blog.csdn.net/Joker_He/article/details/109881899