题393.ARC150-A - Continuous 1(memset超时问题)


题393.ARC150-A - Continuous 1(memset超时问题)


一、题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、题解

本题要求统计使得序列出现连续K个’1’,且除了那连续的K个’1’以外不会在别的地方出现’1’的方案的个数,若方案数为1则输出Yes,否则输出No。
对此我们可以这样去想:固定一个长度为K的区间,左边界为l,右边界为l+K-1,一开始l位于字符串序列开始的位置。在这个区间里,需要满足除了’1’只有’?‘,且所含的’1’为整个字符串序列所有的’1’,这样我们可以保证一个满足题目条件的长度为K的连续的’1’的子序列。之后,我们往右平移区间,直到右边界到字符串的最右边为止,在这个过程中,我们去统计满足要求的区间的个数,若个数为1则Yes,否则为No。
那么如何快速确定一个区间除了’1’只有’?‘,且’1’的个数为整个字符串序列的’1’的个数呢?用前缀和!我们可以从左往右扫描一遍序列,统计到每个位置时’1’的个数pre1[i]和’0’的个数pre0[i],以及顺带统计整个序列所含的’1’的个数cnt1。这样,区间[l,r]的’0’的个数为pre0[r]-pre0[l-1],当该值等于0时即区间中只含’1’或者’?';区间[l,r]的‘1’的个数为pre1[r]-pre1[l-1],当该值等于cnt1时即区间中含的’1’个数为整个字符串所含的’1’的个数。则满足题目条件的方案数+1。
需要注意的是,这里其实可以不用memset初始化前缀和数组,用了直接两千多ms超时,不用就十几ms就过去了,emmm,码算法题几年了,第一次知道memset这么耗时的???

在这里插入图片描述
在这里插入图片描述
代码如下:

//AC代码
#include <bits/stdc++.h>

#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define pb push_back
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int Inf=0x3f3f3f3f;

const int maxn=1e6+1;

int N,K;
char str[maxn];
int pre0[maxn],pre1[maxn];//pre0[i]表示到下标为i的字符时,0的个数;pre1[i]表示到下标为i的字符时,1的个数

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //memset pre数组:由于加了超时因此去掉了(这里因为前缀和数组的开始位置的元素一定为0,所以可以直接由前面的元素去更新后面的元素而不用额外初始化)
        scanf("%d%d",&N,&K);
        scanf("%s",str+1);
        int cnt1=0;
        rep(i,1,N+1)
        {
            pre0[i]=pre0[i-1];
            pre1[i]=pre1[i-1];
            if(str[i]=='0')
            {
                pre0[i]++;//若当前字符为0,则到i的0的个数++
            }
            else if(str[i]=='1')
            {
                pre1[i]++;//若当前字符为1,则到i的1的个数++
                cnt1++;//统计序列中1的个数
            }
        }
        int success=0;
        for(int l=1,r=l+K-1;r<=N;l++,r++)
        {
            //长度为K的区间[l,r]中只有1或者?,并且序列所有的1都在其中
            if(pre0[r]-pre0[l-1]==0&&pre1[r]-pre1[l-1]==cnt1)
            {
                success++;//因为除了1只有?,则可将?全转1即可得到K长度的连续1子序列
            }
        }
        if(success==1)
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
}

//TLE代码
#include <bits/stdc++.h>

#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define pb push_back
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int Inf=0x3f3f3f3f;

const int maxn=1e6+1;

int N,K;
char str[maxn];
int pre0[maxn],pre1[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(pre0,0,sizeof pre0);
        memset(pre1,0,sizeof pre1);
        scanf("%d%d",&N,&K);
        scanf("%s",str+1);
        int cnt1=0;
        rep(i,1,N+1)
        {
            pre0[i]=pre0[i-1];
            pre1[i]=pre1[i-1];
            if(str[i]=='0')
            {
                pre0[i]++;
            }
            else if(str[i]=='1')
            {
                pre1[i]++;
                cnt1++;
            }
        }
        int success=0;
        for(int l=1,r=l+K-1;r<=N;l++,r++)
        {
            //长度为K的区间[l,r]中只有1或者?,并且序列所有的1都在其中
            if(pre0[r]-pre0[l-1]==0&&pre1[r]-pre1[l-1]==cnt1)
            {
                success++;//因为除了1只有?,则可将?全转1则可得到K长度的连续1子序列
            }
        }
        if(success==1)
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值