【题解】CF1615F LEGOndary Grandmaster
将两个串的奇数位取反,那么一次操作相当于邻项交换,我们记录 \(a_i\) 表示 \(s\) 中第 \(i\) 个 \(1\) 的位置,\(b_i\) 表示 \(t\) 中第 \(i\) 个 \(1\) 的位置,那么最小操作数就是 \(\sum|a_i - b_i|\)。
考虑 DP,这里提供一个不同的 DP 方法。
我们定义状态 \(g_{i,j}\) 表示 \(s_i = t_j = 1\),且 \(s_i\) 和 \(t_j\) 匹配的方案数,\(f_{i,j}\) 则表示所有方案的距离之和。
那么我们可以枚举 \(u,v\) 转移,\(g_{i,j} = \sum\limits_{u,v}g_{u,v}\),\(f_{i,j} = g_{i,j} + \sum\limits_{u,v}f_{u,v}\),其中需要满足 \(s\) 串的 \(u,i\) 之间没有 \(1\),\(t\) 串的 \(v,j\) 之间没有 \(1\),因为我们枚举的是上一对匹配的 \(1\)。
不难发现每次转移是一个子矩阵和,二维前缀和优化即可,时间复杂度 \(\mathcal{O}(N^2)\)。
#define N 2005
int n, f[N][N], g[N][N], s[N][N], t[N][N], p[N], q[N]; char a[N], b[N];
int w(int op,int x,int y,int X,int Y){
if(1 == op){
if(!x && !y)return s[X][Y];
if(!x)return s[X][Y] - s[X][y - 1];
if(!y)return s[X][Y] - s[x - 1][Y];
return s[X][Y] - s[x - 1][Y] - s[X][y - 1] + s[x - 1][y - 1];
}
if(!x && !y)return t[X][Y];
if(!x)return t[X][Y] - t[X][y - 1];
if(!y)return t[X][Y] - t[x - 1][Y];
return t[X][Y] - t[x - 1][Y] - t[X][y - 1] + t[x - 1][y - 1];
}
void solve(){
read(n);
scanf("%s%s", a + 1, b + 1);
rp(i, n)if(i & 1){
if(a[i] != '?')a[i] ^= 1;
if(b[i] != '?')b[i] ^= 1;
}
++n, a[n] = b[n] = '1';
rp(i, n){
if(a[i - 1] == '1')p[i] = i - 1; else p[i] = p[i - 1];
if(b[i - 1] == '1')q[i] = i - 1; else q[i] = q[i - 1];
}
rp(i, n)rp(j, n){
f[i][j] = g[i][j] = 0;
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
t[i][j] = t[i - 1][j] + t[i][j - 1] - t[i - 1][j - 1];
ad(s[i][j], 0), su(s[i][j], 0), ad(t[i][j], 0), su(t[i][j], 0);
if(a[i] != '0' && b[j] != '0'){
ad(g[i][j], (w(0, p[i], q[j], i - 1, j - 1) % P + P) % P), ad(f[i][j], (w(1, p[i], q[j], i - 1, j - 1) % P + P) % P);
ad(f[i][j], g[i][j] * 1LL * abs(i - j) % P);
}
ad(s[i][j], f[i][j]), ad(t[i][j], g[i][j]);
}
printf("%d\n", f[n][n]);
}
int main() {
g[0][0] = 1;
rep(i, 0, N - 5)t[0][i] = t[i][0] = 1;
int T; read(T);
while(T--)solve();
return 0;
}