新年第二天写了一道很有意思的题。
首先定义\(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;
}