Codeforces Round #807 (Div. 2) D. Mark and Lightbulbs

 

 翻译:

马克刚买了一架𝑛灯泡。灯泡的状态可以用二进制字符串𝑠=𝑠1𝑠2…𝑠𝑛来描述,其中𝑠𝑖=𝟷表示𝑖-th灯泡是打开的,而𝑠𝑖=𝟶表示𝑖-th灯泡是关闭的。

不幸的是,灯泡坏了,他唯一能做的改变灯泡状态的操作是:

选择一个指数𝑖从2、3、…,𝑛−1这样𝑠𝑖−1≠𝑠𝑖+ 1。
切换𝑠𝑖。即,如果𝑠𝑖为𝟶,则将𝑠𝑖设置为𝟷,反之亦然。
Mark希望灯泡的状态是另一个二进制字符串𝑡。帮助Mark确定这样做的最小操作数。

输入
输入的第一行包含单个整数𝑞(1≤𝑞≤104)—测试用例的数量。

每个测试用例的第一行包含单个整数𝑛(3≤𝑛≤2⋅105)——灯泡的数量。

每个测试用例的第二行包含一个长度为𝑛的二进制字符串𝑠——灯泡的初始状态。

每个测试用例的第三行包含一个长度为𝑛的二进制字符串𝑡——灯泡的最终状态。

保证所有测试用例𝑛的总和不超过2⋅105。

输出
对于每个测试用例,打印一行,其中包含Mark将𝑠转换为𝑡所需执行的最小操作数。如果没有这样的操作顺序,则打印−1。

例子
inputCopy
4
4
0100
0010
4
1010
0100
5
01001
00011
6
000101
010011
outputCopy
2
-1
-1
5
请注意
在第一个测试用例中,实现最小操作数量的操作序列如下所示。

选择𝑖=3,将𝟶𝟷𝟶𝟶更改为𝟶𝟷𝟷𝟶。
选择𝑖=2,将𝟶𝟷𝟷𝟶更改为𝟶𝟶𝟷𝟶。
在第二个测试用例中,没有操作序列,因为不能更改𝑠的第一个数字或最后一个数字。
在第三个测试用例中,即使𝑠和𝑡的第一个数字是相同的,𝑠和𝑡的最后一个数字是相同的,但可以表明不存在满足条件的操作序列。

在第四个测试用例中,实现最小操作次数的一个序列如下:

选择𝑖= 3,改变𝟶𝟶𝟶𝟷𝟶𝟷,𝟶𝟶𝟷𝟷𝟶𝟷。
选择𝑖= 2,改变𝟶𝟶𝟷𝟷𝟶𝟷,𝟶𝟷𝟷𝟷𝟶𝟷。
选择𝑖= 4,改变𝟶𝟷𝟷𝟷𝟶𝟷,𝟶𝟷𝟷𝟶𝟶𝟷。
选择𝑖= 5,改变𝟶𝟷𝟷𝟶𝟶𝟷,𝟶𝟷𝟷𝟶𝟷𝟷。
选择𝑖= 3,改变𝟶𝟷𝟷𝟶𝟷𝟷,𝟶𝟷𝟶𝟶𝟷𝟷。

思路:

这道题利用其性质来写 0 1 1 1 0 0

如果要变成         0 0 0 1 1 0

则需要移动         0 1 2 2 3 ,一共3步

相对应的,就可以变成 0 1 0 0 1 0

                 0 0 0 1 0 1

就是其对应的1的位置相减,1的块数还要相等,所以判断块数来决定是否是-1,然后总花费就是abs(i-j)

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
#include<stack>
using namespace::std;
typedef long long  ll;
int n,t;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
//这道题利用其性质来写 0 1 1 1 0 0
//如果要变成         0 0 0 1 1 0
//则需要移动         0 1 2 2 3 ,一共3步
//相对应的,就可以变成 0 1 0 0 1 0
//                 0 0 0 1 0 1
//就是其对应的1的位置相减,1的块数还要相等,所以判断块数来决定是否是-1,然后总花费就是abs(i-j)
string a,b;
int a1[200005],b1[200005];
void solv(){
    cin>>n>>a>>b;
    for (int i =n-1; i>=0; i--) {
        a1[i]=a[i]-'0';
    }
    for (int i =n-1; i>=0; i--) {
        b1[i]=b[i]-'0';
    }
    if (a[0]!=b[0]||a[n-1]!=b[n-1]) {
        printf("-1\n");return;
    }
    int kkl=0;
    for (int i=n-1; i>0; i--) {
        a1[i]=a1[i]^a1[i-1];
        if (a1[i]==1) {
            kkl++;
        }
    }
    for (int i=n-1; i>0; i--) {
        b1[i]=b1[i]^b1[i-1];
        if (b1[i]==1) {
            kkl--;
        }
    }
    if (kkl!=0) {
        printf("-1\n");return;
    }
//    for (int i = 0; i<n; i++) {
//        printf("%d ",a1[i]);
//    }printf("\n");
//    for (int i = 0; i<n; i++) {
//        printf("%d ",b1[i]);
//    }printf("\n");
    ll ans=0;
    for (int i =n-1,j=n-1; i&&j;) {
//        printf("%d %d\n",i,j);
        if (a1[i]&&b1[j]) {
            
            ans+=abs(i-j);
            i--;
            j--;
            continue;
        }
        if (a1[i]) {
            j--;
        }
        else{
            i--;
        }
    }
    printf("%lld\n",ans);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>t;
    while (t--) {
        solv();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值