Loading

【题解】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; 
}
posted @ 2022-03-05 19:49  7KByte  阅读(58)  评论(0编辑  收藏  举报