晚自修想了十几 min,胡了一个做法。
考虑它这个 \(n,m\) 很小,猜测可能上到指数级别。考虑先分析放的操作,不难发现几个性质。
-
若 \((i,j)\) 能够放置,当且仅当 \((i,j)\) 为空,且 \((1,1),(i,j)\) 这个矩形除了 \((i,j)\) 都已放置。证明考虑要放置 \((i,j)\),则 \((x,j),(i,y)\) 都应该放置,而这些要放置则又是约束,可看成横竖 2 条直线的限制。
-
每个时刻的放置状态一定呈倒三角阶梯状。即对于每列的行数单调不增。证明考虑下性质 1 即可反证。
那么,这样暴力还是会有 \(10^{10}\) 状态数。
但是考虑 dp 转移,发现枚举拐点,然后再枚举每个拐点那一层代表的高度即可,状态数只有 \(\sum_{i} \binom{m}{i} \binom{n+1}{i}\) 种,即枚举每列平台个数,再枚举平台高度。
熄灯了
然后预处理下记忆化搜索即可。
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N=(int)(1e6+5);
map<vector<int>,int>mp;
vector<vector<int> >p;
vector<int>vec[12],vec2[13],tmp,v;
ll f[N];
bool vis[N];
int n,m,a[11][11],b[11][11],tot,ed;
ll dfs(int x) {
if(x==ed) {
return 0ll;
}
if(vis[x]) return f[x];
bool fl=0; int res=0;
for(int i:p[x]) {
res+=i;
}
if(res&1) fl=1;
else fl=0;
for(int i=0;i<p[x].size();i++) {
int qwq=p[x][i];
if(p[x][i]+1>n) continue ;
bool ok=1;
for(int j=0;j<i;j++) {
if(p[x][j]<p[x][i]+1) ok=0;
}
if(ok) {
v.clear();
for(int j=0;j<i;j++) v.pb(p[x][j]);
v.pb(p[x][i]+1);
for(int j=i+1;j<p[x].size();j++) v.pb(p[x][j]);
int NEX=mp[v];
// cout<<x<<" "<<f[x]<<" "<<qwq<<" : "<<i<<" "<<fl<<" ";
if(!fl) {
f[x]=max(f[x],dfs(NEX)+a[qwq+1][i+1]);
} else {
// cout<<b[qwq+1][i+1]<<'\n';
f[x]=min(f[x],dfs(NEX)-b[qwq+1][i+1]);
}
}
}
// cout<<x<<" "<<f[x]<<'\n';
vis[x]=1;
return f[x];
}
signed main() {
cin.tie(0); ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>b[i][j];
for(int S=0;S<(1<<m);S++) {
if(S&1) vec[__builtin_popcount(S)].pb(S);
}
for(int S=0;S<(1<<(n+1));S++) {
vec2[__builtin_popcount(S)].pb(S);
}
tot=-1;
for(int i=1;i<=m;i++) {
for(int S:vec[i]) {
for(int T:vec2[i]) {
v.clear(); tmp.clear();
for(int j=0;j<=n;j++) {
if((T>>j)&1) tmp.pb(j);
}
int las=-1;
for(int j=1;j<=m;j++) {
if((S>>(j-1))&1) {
v.pb(las=tmp.back());
tmp.pop_back();
} else {
v.pb(las);
}
}
// if(v.empty()) {
// cout<<S<<' '<<T<<'\n';
// }
mp[v]=++tot; p.pb(v);
bool fl=1; int res=0;
for(int x:v) {
res+=x;
if(x!=n) fl=0;
}
if(res&1) f[tot]=(ll)(2e16);
else f[tot]=-(ll)(2e16);
if(fl) {
ed=tot;
}
// cout<<tot<<'\n';
// for(int x:v) cout<<x<<" ";
// cout<<'\n';
}
}
}
cout<<dfs(0);
return 0;
}