Bestcoder-892-1002-Binary Addition(HDU6839)

题目链接

题目链接(可提交)

题意:

两个长为n(1e5)的二进制串a、b,小地址为低位,现在提供两种操作(任意更改一位,或整串二进制加以),问最少多少步可以使a串变为b串

思路:

策略题首先需要分析两种不同策略的优劣以及应用场景

对于操作一,显然是基本操作,按位变换,最暴力的做法

而相比较而言,操作二就是用来优化的,在某些特殊场景下,操作二可以对串造成较大的变化。

显然,若从最低位开始有连续多个1时,一次操作二可以将这一系列多个连续的1全都变成0,从而达到一步操作更改多位的效果。

而又由于这种操作二所带来的多位变化必须从最低位开始,因此注定这种操作只能使用一次。

那么,本题的策略当然就是巧用操作二, 通过构造从最低位起一定长度的连续1来优化速度。

例如:如果我们想构造长度为k的连续1串,那么总的策略即可经过以下六步即可完成:

1.通过操作一将0~(k-1)位中所有的0都变为1,从而完成构造

2.若第k位为1,需要对这一位使用一次操作1使其变为0,防止构造的连续1的串超长

3.通过一次操作2将0~(k-1)位中都变为0,将第k位变成1

4.检查目标串中的0~(k-1)位,通过操作一将实现对应的1

5.检查目标串中的第k位,若为0,则需要使用一次操作一来使该位与目标串相同

6.检查(k+1)位直至末尾所有位,若有不相同的位则利用操作一变换完成

其实不难发现,策略一,策略四和策略六都可以通过预处理实现

而策略二,策略三和策略五都仅通过一步就可以完成

于是,我们只需要枚举所需构造的连续1串的长度k即可

最后注意两种特殊情况:

1.暴力全使用操作一就是最优策略,不需要使用操作二,这种情况可以在初始化的时候就直接考虑掉

2.需要构造的连续1串的长度和原串相同,即策略五不需要再执行,这里我们可以在初始化的过程中,将策略五多初始化两位并定位0,即可实现。此外,这种情况下,操作二的进位会在第n位,比原串长,这就是为什么原题目并没有直接说串长为n,而说的是无限长串第n位及以后均为0,这就需要我们手动补0将两串都延长一位。

代码:

/*
Author Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn = 1e5+5;

char s[maxn],t[maxn];
int diff[maxn],chag[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        //freopen(".txt","r",stdin);
        //ios::sync_with_stdio(false);
        //cin.tie(0);
        scanf("%s%s",s,t);
        diff[n] = 0;
        diff[n+1] = 0;
        for(int i=n-1;i>=0;i--)
        {
            diff[i] = diff[i+1];
            if(s[i]!=t[i])
                diff[i]++;
        }
        t[n] = '0';
        s[n] = '0';
        chag[0] = 0;
        if(s[0]=='0')
            chag[0]++;
        if(t[0]=='1')
            chag[0]++;
        /*if(t[1]=='0')
            chag[0]++;
        */
        for(int i=1;i<n;i++)
        {
            chag[i] = chag[i-1];
            if(s[i]=='0')
                chag[i]++;
            if(t[i]=='1')
                chag[i]++;
            /*else
                chag[i]--;
            if(t[i+1]=='0')
                chag[i]++;*/
        }
        int re = diff[0];
        for(int i=0;i<n;i++)
        {
            /*if(s[i+1]=='1')
                continue;*/
            int now = chag[i] + diff[i+2] + 1;
            if(t[i+1]=='0')
                now++;
            if(s[i+1]=='1')
                now++;
            re = re>now?now:re;
        }
        //re = re>chag[n-1]?chag[n-1]:re;
        printf("%d\n",re);
        /*for(int i=0;i<n;i++)
            cout << diff[i];
        cout << endl;
        for(int i=0;i<n;i++)
            cout << chag[i];
        cout << endl;*/
    }
    return 0;
}

/*
注意进位后下一位的状况
预处理防止连续进位
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值