题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");
}
}
}