JZYZOJ 1629 马棚

新年第二天写了一道很有意思的题。

首先定义\(f[i][j]\)为前\(i\)头牛用了前\(j\)个牛棚的最小违和值

\(black[i]\)\(white[i]\)是前i个牛有多少白牛多少黑牛

\(k\)是前\(k\)头牛用了前\(j-1\)个牛棚

\(get(a,b)\)\(a\)\(b\)之间所有牛的违和值

所以状态转移方程为f[i][j] = min(f[k][j-1]+get(k,i))

有了状态转移方程这到题就很好写了

coding

#include <bits/stdc++.h>
using namespace std;


const int N = 505;
int n,k,black[N] = {},white[N] = {},f[N][N] = {};


inline int read()
{
    register int x = 0;
    register char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9')
    {
        x = (x<<3)+(x<<1) + ch-'0';
        ch = getchar();
    }
    return x;
}

inline int get(int l,int r)
{
    return (black[r]-black[l])*(white[r]-white[l]);
}


int main()
{
    memset(f,0x7f7f7f7f,sizeof(f)); f[0][0] = 0;
    n = read(); k = read();
    for(register int i = 1;i <= n;i++)
    {
        register int x = read();
        if(x)
        {
            black[i] = black[i-1]+1;
            white[i] = white[i-1];
        }
        else
        {
            black[i] = black[i-1];
            white[i] = white[i-1]+1;
        }
    }
    for(register int j = 1;j <= k;j++)
    {
        for(register int i = j;i <= n;i++)
        {
            for(register int k = j-1;k <= i-1;k++)  
            {
                f[i][j] = min(f[i][j],f[k][j-1]+get(k,i));
            }
        }
    }
    
    printf("%d\n",f[n][k]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mark-X/p/11699585.html