21.6.23 t2
tag:轮廓线dp
手玩一下会发现,最少需要4个镜子才能减少答案,多玩一下就能发现,减少的答案就等于镜子形成的回路长度。
\(ans=4nm-2len\)
为了计算这个东西,可以理解为,从镜子射出光线,然后贡献就是那些没有到达边界的光线的总长度。
然后问题就变成了,放 \(k\) 个镜子,形成的封闭光路最多有多长(可以不连通)
直接轮廓线 \(dp\) 就行,分讨见代码。
\(O(nm2^{\min(n,m)})\)
最后记得求前缀 \(\min\)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void Read(T &n){
char ch; bool flag=false;
while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
if(flag)n=-n;
}
int n, m;
int f[2][36][1<<6];
char a[10][10], tmp[10][10];
inline void upd(int &a, int b){if(b>a) a = b;}
int main(){
// freopen("2.in","r",stdin);
// freopen("2.out","w",stdout);
int T; Read(T);
while(T--){
Read(n); Read(m);
for(int i=0; i<n; i++) scanf("%s",a[i]);
if(n<m){
for(int i=0; i<n; i++) for(int j=0; j<m; j++) tmp[j][n-i-1] = a[i][j], a[i][j] = 0;
swap(n,m);
for(int i=0; i<n; i++) for(int j=0; j<m; j++) a[i][j] = tmp[i][j], tmp[i][j] = 0;
}
// for(int i=0; i<n; i++) printf("%s\n",a[i]);puts("");
char opt = 0; memset(f[opt],-1,sizeof f[opt]);
f[opt][0][0] = 0; int tp = 1<<(m+1);
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
char nxt = opt^1;
memset(f[nxt],-1,sizeof f[nxt]);
for(int k=0; k<=i*m+j; k++) for(int S=0; S<tp; S++) if(f[opt][k][S]>=0){
char v1 = S>>j&1, v2 = S>>(j+1)&1, nxtS;
int val = f[opt][k][S];
if(v1==0 and v2==0){
// not place
upd(f[nxt][k][S],val);
// place "/"
if(a[i][j]=='1' and i!=n-1 and j!=m-1)
nxtS = S,
nxtS |= 1<<j,
nxtS |= 1<<(j+1),
upd(f[nxt][k+1][nxtS],val+1);
}
if(v1==0 and v2==1){
// not place
if(i!=n-1)
nxtS = S,
nxtS ^= 1<<(j+1),
nxtS |= 1<<j,
upd(f[nxt][k][nxtS],val+1);
// place "\"
if(a[i][j]=='1' and j!=m-1)
upd(f[nxt][k+1][S],val+1);
}
if(v1==1 and v2==0){
// not place
if(j!=m-1)
nxtS = S,
nxtS ^= 1<<j,
nxtS |= 1<<(j+1),
upd(f[nxt][k][nxtS],val+1);
// place "\"
if(a[i][j]=='1' and i!=n-1)
upd(f[nxt][k+1][S],val+1);
}
if(v1==1 and v2==1){
// not place (or place "\")
if(i!=n-1 and j!=m-1)
upd(f[nxt][k][S],val+2);
// place "/"
if(a[i][j]=='1')
nxtS = S,
nxtS ^= 1<<j,
nxtS ^= 1<<(j+1),
upd(f[nxt][k+1][nxtS],val+1);
}
}
opt ^= 1;
}
if(i!=n-1){
char nxt=opt^1;
memset(f[nxt],-1,sizeof f[nxt]);
for(int k=0; k<=(i+1)*m; k++) for(int S=0, tpS=(1<<m); S<tpS; S++) if(f[opt][k][S]>=0) f[nxt][k][S<<1] = f[opt][k][S];
opt ^= 1;
}
}
f[opt][0][0] = max(f[opt][0][0],0);
for(int k=1; k<=n*m; k++) upd(f[opt][k][0],f[opt][k-1][0]);
for(int k=0; k<=n*m; k++) printf("%d ",n*m*4-max(f[opt][k][0],0)*2);puts("");
}
return 0;
}