2020-9-26 中国计量大学程序设计竞赛同步赛 B

在牛客网上打的,我还蛮喜欢这些大学的比赛的,比打VJ,CF和CCPC,ICPC的往年题目有趣多了,可能是外国人的脑洞我不习惯吧,中国人出的题还是舒服。

这里记录一下B,因为做这个题的过程对我很有启发。

一开始是这样的代码:

#include <bits/stdc++.h>
using namespace std;

const int manx=1e5+10;
int t;
int s[manx],s2[manx];
char a[manx],b[manx],c[manx];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(s,0,sizeof(s));
        memset(s2,0,sizeof(s2));
        scanf("%s",a);
        scanf("%s",b);
        int n=strlen(a);
        int k=1,k2=1;
        for(int i=0; i<n; i++)//两重循环,加三个if判断,这一代码块会超时
        {
            if(a[i]!=b[i])
            {
                for(int j=i; j<n; j++) 
                {
                    if(a[j]=='0')
                    {
                        a[j]='1';
                    }
                    else if(a[j]=='1')
                    {
                        a[j]='0';
                    }
                }
                s[k++]=i;
            }
        }
        s2[k2++]=-1;
        for(int i=0;i<n;i++) //还用遍历方式更新值,也很浪费时间
        {
          c[i]='0';
        }
        for(int i=0; i<n; i++) //同第一个大循环,两重循环三个判断,超时
        {
            if(c[i]!=b[i])
            {
                for(int j=i; j<n; j++)
                {
                    if(c[j]=='0')
                    {
                        c[j]='1';
                    }
                    else if(c[j]=='1')
                    {
                        c[j]='0';
                    }
                }
                s2[k2++]=i;
            }
        }
        //printf("%s %s\n",a,c);
        //printf("%d %d\n",k,k2);
        if(k<=k2)
        {
            for(int i=1; i<k; i++)
            {
                if(i!=k-1)
                    printf("%d ",s[i]+1);
                else
                    printf("%d\n",s[i]+1);
            }
        }
        else
        {
            for(int i=1; i<k2; i++)
            {
                if(i!=k2-1)
                    printf("%d ",s2[i]+1);
                else
                    printf("%d\n",s2[i]+1);
            }
        }
    }
    return 0;
}

这是最开始,我想着模拟(虽然知道很可能超时,但是还是抱着侥幸心理)一种是他不先把数全变成0,直接变;一种是全变成0后再开始变,这样就是两种情况,取步数少的那种。但是我们看到n最大为1e5,我每变一次,就更新这个数后面的所有数的值(1变0,0变1)其时间复杂度立刻增大了一倍,会超时的。
之后我就想到了一句话,山不向我走来,我就向山走去。
我尝试不用每变一个数,后面的数跟着变,而是设一个num,这个num就是我当前数组应该是1或者0,但我用num保存这个值,这样我就不用遍历后面的数了,因为说到底,每次判断变或者不变后面的数(和模板串一样就不变,不一样就变)是由当前这个数决定的,所以我只要用num保存当前数的状态就行啦!
一开始用的不彻底,出现了半成品,依旧超时,只改了下半部分,没改上半部分,因为上半部分不好改。

#include <bits/stdc++.h>
using namespace std;

const int manx=1e5+10;
int t;
int s[manx],s2[manx];
char a[manx],b[manx];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(s,0,sizeof(s));
        memset(s2,0,sizeof(s2));
        scanf("%s",a);
        scanf("%s",b);
        int n=strlen(a);
        int k=1,k2=1;
        for(int i=0; i<n; i++)
        {
            if(a[i]!=b[i])
            {
                for(int j=i; j<n; j++)
                {
                    if(a[j]=='0')
                    {
                        a[j]='1';
                    }
                    else if(a[j]=='1')
                    {
                        a[j]='0';
                    }
                }
                s[k++]=i;
            }
        }
        s2[k2++]=-1;
        char num='0';
        for(int i=0; i<n; i++)
        {
            if(num!=b[i])
            {
                if(num=='0')
                {
                    num='1';
                }
                else if(num=='1')
                {
                    num='0';
                }

                s2[k2++]=i;
            }
        }



        //printf("%d %d\n",k,k2);
        if(k<=k2)
        {
            for(int i=1; i<k; i++)
            {
                if(i!=k-1)
                    printf("%d ",s[i]+1);
                else
                    printf("%d\n",s[i]+1);
            }
        }
        else
        {
            for(int i=1; i<k2; i++)
            {
                if(i!=k2-1)
                    printf("%d ",s2[i]+1);
                else
                    printf("%d\n",s2[i]+1);
            }
        }
    }
    return 0;
}

之后我又改了上半部分,过了!但是我用的不是num存储当前状态的数字了(0/1)而是用个flag判断当前我是和他相同对,还是和他不同才对。这点可能不好理解,因为确实是当时急中生智想出来的,我也解释不太好,请看代码。

#include <bits/stdc++.h>
using namespace std;

const int manx=1e5+10;
int t;
int s[manx],s2[manx];
char a[manx],b[manx];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",a);
        scanf("%s",b);
        int n=strlen(a);
        int k=1,k2=1;
        int flag=0;
        for(int i=0; i<n; i++)
        {
            if(a[i]!=b[i]&&flag==0)
            {
                s[k++]=i;
                flag=1;
            }
            else if(a[i]==b[i]&&flag==1)
            {
                s[k++]=i;
                flag=0;
            }
        }


        s2[k2++]=-1;
        char num='0';
        for(int i=0; i<n; i++)
        {
            if(num!=b[i])
            {
                if(num=='0')
                {
                    num='1';
                }
                else if(num=='1')
                {
                    num='0';
                }

                s2[k2++]=i;
            }
        }



        //printf("%d %d\n",k,k2);
        if(k<=k2)
        {
            for(int i=1; i<k; i++)
            {
                if(i!=k-1)
                    printf("%d ",s[i]+1);
                else
                    printf("%d\n",s[i]+1);
            }
        }
        else
        {
            for(int i=1; i<k2; i++)
            {
                if(i!=k2-1)
                    printf("%d ",s2[i]+1);
                else
                    printf("%d\n",s2[i]+1);
            }
        }
    }
    return 0;
}

我想到的山不向我走来,我就向山走去的思路,其实很多时候我们都能用到, 即换位思考,逆向思维,但是在实际应用中,应该要灵活使用才好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值