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;
}

浙公网安备 33010602011771号