若貓和狗中至少有一個出現了$0$次,那麼答案顯然是$0$,否則若獅子出現了$0$次,那麼顯然無解。
那麼現在至少有一個動物保持原地不同,其它動物恰好移動一次。
如果全部貓都不動而全部狗都動,那麼可以貪心求出答案,最多移動一個獅子。
同理可以處理全部貓動而全部狗都不動的情況。
現在考慮同時存在貓和狗不動的情況,那麼動的貓和狗一定是移動到不動的同類旁邊,而獅子起到間隔作用。
設$f[i][j][k][S]$表示考慮前$i$個動物,目前手上剩餘可以調控的獅子數為$j$(可以為負,表示後面的獅子往前動),下一個動物可以是$k$,不動的動物種類為$S$的最小移動次數,直接轉移即可。
時間複雜度$O(n^2)$。
#include<cstdio> const int N=5010,inf=1000000; int Case,n,m,o,i,j,k,S,w,a[N],b[N],cnt[3],f[2][N*2][2][4],ans; inline void up(int&a,int b){a>b?(a=b):0;} int cal(int x){ int i,t=0; for(i=1;i<=n;i++)if(a[i]!=(x^1))b[++t]=a[i]; for(i=1;i<t;i++)if(b[i]==2&&b[i+1]==2)return n-t; if(b[1]==2||b[t]==2)return n-t; return n-t+1; } int solve(){ scanf("%d",&n); for(i=0;i<3;i++)cnt[i]=0; for(i=1;i<=n;i++)scanf("%d",&a[i]),cnt[a[i]]++; if(!cnt[0]||!cnt[1])return 0; if(!cnt[2])return -1; m=cnt[2]; up(m,n/2+5); for(o=0,j=-m;j<=m;j++)for(k=0;k<2;k++)for(S=0;S<4;S++)f[0][j+N][k][S]=inf; f[0][N][0][0]=f[0][N][1][0]=0; for(i=0;i<n;i++,o^=1){ for(j=-m;j<=m;j++)for(k=0;k<2;k++)for(S=0;S<4;S++)f[o^1][j+N][k][S]=inf; if(a[i+1]==0)for(j=-m;j<=m;j++)for(k=0;k<2;k++)for(S=0;S<4;S++)if(f[o][j+N][k][S]<inf){ w=f[o][j+N][k][S]; up(f[o^1][j+N][k][S],w+1); up(f[o^1][j+N-(k==1)][0][S|1],w); } if(a[i+1]==1)for(j=-m;j<=m;j++)for(k=0;k<2;k++)for(S=0;S<4;S++)if(f[o][j+N][k][S]<inf){ w=f[o][j+N][k][S]; up(f[o^1][j+N][k][S],w+1); up(f[o^1][j+N-(k==0)][1][S|2],w); } if(a[i+1]==2)for(j=-m;j<=m;j++)for(k=0;k<2;k++)for(S=0;S<4;S++)if(f[o][j+N][k][S]<inf){ w=f[o][j+N][k][S]; up(f[o^1][j+N+1][k][S],w+1); up(f[o^1][j+N][0][S],w); up(f[o^1][j+N][1][S],w); } } ans=cal(0); up(ans,cal(1)); for(k=0;k<2;k++)up(ans,f[o][N][k][3]); return ans; } int main(){ scanf("%d",&Case); while(Case--)printf("%d\n",solve()); return 0; }