CF2000F Color Rows and Columns 題解

Sorato發表於2024-08-15

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;
}

相關文章