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