Codeforces Round #807 (Div. 2)D

[Codeforces Round #807 (Div. 2)D](Problem - D - Codeforces (Unofficial mirror by Menci))

大概题意:

给两个长度为n(n <= 2e5)的01字符串,问是否可以在给定规则下相互转化,如果可以,输入最小步数。

规则:对于i(1 < i < n), 如果有s[i -1] != s[i + 1],s[i]可以在0和1中任意取值。

注意有多组数据。

思路历程:

1,发现不能变化的串:0101010101,得知只有0重合时或1重合时才可以变化,但不能全为0或全为1。

2,发现串010000,中间的1000每个都可以任意变化,但不能变成1011这种1001。

3,发现串01000010,中间的两个1无法重合,得出方案是否存在的条件:1的堆数必须相同,边界必须相同。

4,统计答案,对还原的操作序列按操作1堆的序数排序,可得到最小方案就是第一堆对第一堆,第二堆对第二堆,直到最后一堆。答案也是这样算,记L0,R0和L1,R1为两堆1的左右,当前堆的答案就是abs(L0 - L1) + abs(R0 - R1);

以上4步,我花了1个半小时。

下面是代码:

#include<cstdio>

const int maxn = 2e5 + 10;

char s[2][maxn];
int n, cnt[2], L[2][maxn], R[2][maxn];

int abs(int x) { return x > 0 ? x : -x; }

int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		for(int i = 0; i < 2; i++) scanf("%s", s[i] + 1);

		cnt[0] = cnt[1] = 0;
		for(int k = 0; k < 2; k++)
			for(int i = 1; i <= n; i++) {
				if(s[k][i] == '0') continue;
				int j;
				for(j = i; (j + 1 <= n) && s[k][j + 1] == '1'; j++);
				L[k][++cnt[k]] = i; R[k][cnt[k]] = j;
				i = j;
			}
		if(cnt[0] != cnt[1] || s[0][n] != s[1][n] || s[0][1] != s[1][1]) { printf("-1\n"); continue; }
		long long ans = 0;
		for(int i = 1; i <= cnt[0]; i++) ans += abs(L[0][i] - L[1][i]) + abs(R[0][i] - R[1][i]);
		printf("%lld\n", ans);
	}
	return 0;
}

posted @ 2022-07-16 16:29  漠视&漠视  阅读(41)  评论(0)    收藏  举报