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