CF2000F Color Rows and Columns 题解

CF2000F Color Rows and Columns 题解

题目大意

给定 \(N\) 个矩形,第 \(i\) 个矩形规格为 \(a_i\times b_i\)。对这些矩形的单元格涂色,若一个矩形的一行或一列都被涂上了色,则获得 \(1\) 的价值。求获得 \(M\) 价值至少要涂多少个单元格。

Solve

考虑 dp。

\(f_{i,j}\) 表示前 \(i\) 个矩形,恰好获得 \(j\) 价值的最小代价。如何状态转移?

如果我钦定第 \(i\) 个矩形中恰好获得 \(k\) 价值,即涂满的行和列之和为 \(k\leq j\),最小代价 \(v_{i,k}\) 是多少?

考虑枚举涂了 \(x\) 列,\(k-x\) 行,则代价为 \(ax+b(k-x)-ab\),要减去重叠部分。此表达式形如二次函数,复杂度允许,故枚举 \(x\) 找到代价最小值 \(v_{i,k}\) 即可。

有状态转移:\(f_{i,j}=\min\limits_{k=0}^j\{f_{i-1,j-k}+v_{i,k}\}\)。时间复杂度 \(O(nk^2)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	short f=1;
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
const int N=1010,M=110;
int t,n,m,a,b,f[N][M];
signed main()
{
	t=read();
	while(t--)
	{
		n=read();m=read();
		for(int i=0;i<=n;i=-~i)
			for(int j=1;j<=m;j=-~j)
				f[i][j]=1e18;
		for(int i=1;i<=n;i=-~i)
		{
			a=read();b=read();
			for(int j=0;j<=m&&j<=a+b;j=-~j)
			{
				int mn=1e18;
				for(int k=max(0ll,j-a);k<=j&&k<=b;k=-~k)
					mn=min(mn,k*a+(j-k)*b-k*(j-k));
				for(int k=j;k<=m;k=-~k)
					f[i][k]=min(f[i][k],f[i-1][k-j]+mn);
			}
		}
		printf("%lld\n",f[n][m]==1e18?-1ll:f[n][m]);
	}
	return 0;
}
posted @ 2024-08-15 08:25  Sorato  阅读(54)  评论(0编辑  收藏  举报