*题解:P13323 [GCJ 2012 #1C] Box Factory
解析
设 \(f_{i,j}\) 表示考虑前 \(i\) 段盒子和前 \(j\) 段玩具时的答案。分别讨论扔掉第 \(i\) 段盒子,扔掉第 \(j\) 段玩具,以及让第 \(i\) 段盒子与第 \(j\) 段玩具匹配的情况。前两种情况分别从 \(f_{i - 1,j},f_{i,j - 1}\) 转移即可。对于第三种情况,考虑让第 \(j\) 段一整段玩具去匹配第 \(i\) 段盒子,但问题是我们并不知道第 \(i\) 段盒子已经被前面的玩具匹配了多少个并且值域很大我们无法将其设进状态里。不妨跳出这一段,直接考虑这一种盒子连续匹配多少个玩具。具体地,枚举 \(x,y\) 表示考虑第 \([x + 1,i]\) 段中的盒子以及第 \([y + 1,j]\) 段中的玩具,种类为 \(A_i\) 的盒子能匹配上多少个玩具,那么就有 \(f_{i,j}\leftarrow \max(f_{i,j},f_{x,y} + \min(\operatorname{prea}(A_i,i) - \operatorname{prea}(A_i,x),\operatorname{preb}(B_j,j) - \operatorname{preb}(B_j,y)))\)。其中 \(\operatorname{prea}(a,b)\) 表示种类为 \(a\) 的盒子在前 \(b\) 段中的个数,\(\operatorname{preb}\) 同理。
时间复杂度 \(O(TN^2M^2)\)。
代码
/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 100 + 5, M = 20, P = 450, mod = 998244353, mod2 = 1e9 + 7, b1 = 131;
ll f[N][N];
ll a[N],A[N],b[N],B[N];
ll prea[N][N],preb[N][N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
cin>>T;
int x = 0;
while(T--){
x++;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i]>>A[i];
for(int j=1;j<N;j++){
prea[j][i] = prea[j][i - 1];
}
prea[A[i]][i] += a[i];
}
for(int i=1;i<=m;i++){
cin>>b[i]>>B[i];
for(int j=1;j<N;j++){
preb[j][i] = preb[j][i - 1];
}
preb[B[i]][i] += b[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j] = max(f[i - 1][j],f[i][j - 1]);
if(A[i] == B[j]){
for(int k=0;k<i;k++){
for(int l=0;l<j;l++){
f[i][j] = max(f[i][j],f[k][l] + min(prea[A[i]][i] - prea[A[i]][k],
preb[B[j]][j] - preb[B[j]][l]));
}
}
}
}
}
cout<<"Case #"<<x<<": "<<f[n][m]<<'\n';
}
return 0;
}

浙公网安备 33010602011771号