21.6.23 t2
阿新 • • 發佈:2021-06-24
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; }