2020牛客寒假算法基础集训营1

nozomi和字符串
题解:修改k次,为了使字符串的连续相同的长度尽可能的大,k次操作一定使相同的操作,因此记录下每个0,1的位置,然后连续改变k次。

#include<iostream>
#include<vector>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
vector<int> v0,v1;	
string s;
int main( )
{
	int n,k;
	cin>>n>>k;
	cin>>s;
	v0.push_back(-1);
	v1.push_back(-1);
	for(int i=0;i<n;i++)
	{
		if(s[i]=='0') v0.push_back(i);
		else v1.push_back(i);
	}
	v0.push_back(n);
	v1.push_back(n);
	int maxx=0;
	if(v0.size()-2<=k) maxx=n;
	else
	{
		for(int i=1,j=k;j<=v0.size()-1;i++,j++)
		{
			maxx=max(maxx,v0[j+1]-v0[i-1]-1);//j+1就是i+k的后缀
			//i-1是i的前缀,后缀与前缀的距离就是长度。
		}
	}
	if(v1.size()-2<=k) maxx=n;
	else
	{
		for(int i=1,j=k;j<=v1.size()-1;i++,j++)
		{
			maxx=max(maxx,v1[j+1]-v1[i-1]-1);
		}
	}
	cout<<maxx;
	return 0; 
}

另一种方法:类似于尺取法,一点一点的找,设置双指针移动

#include<iostream>
#include<cmath>
#define maxn 200005
using namespace std;
int a[maxn];
int b[5];
const int inf=0x3f3f3f3f;
int main( )
{
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		char c;
		cin>>c;
		a[i]=c-'0';
	}
	int left,right;
	int ma=0;
	int ans=0;
	for(left=1,right=1;right<=n;right++)//将0改1 
	{
		b[a[right]]++;
		ma=max(ma,b[1]);//目前子串1的个数
		if(right-left+1-ma>k)//right-left+1为当前子串的长度,它减去ma大于k说明要改的0多了 
		b[a[left++]]--;//修改子串位置,并且把原来的数据抹去 
		ans=max(ans,right-left+1);
	}
	ma=0;
	b[0]=0;
	b[1]=0;
	for(left=1,right=1;right<=n;right++)
	{
		b[a[right]]++;
		ma=max(ma,b[0]);
		if(right-left+1-ma>k)
		b[a[left++]]--;//
		ans=max(ans,right-left+1);
	}
	cout<<ans<<endl;
	return 0;
}

二分法(感谢大佬的指教~):首先二分的是答案,答案最小为1,最大为n。,取中间值为mid,查看当答案为mid时是否符合条件,如果符合条件那么尝试最终答案是否可以更大,也就是查mid+1到n,如果不符合,那么缩小长度,查1到mid-1
至于如何看是否符合要求就是设置一个数组从给的字符串第一个位置开始每个数加上前边的数。比如:字符串10101,那么存入数组的就是11223。那么a[i+m-1]-a[i]就是这个区间中1的个数,有了1的个数就知道了0的个数。

#include<iostream>
#include<cmath>
#define maxn 200005
using namespace std;
char a[maxn];
int s[maxn];
int l,r;	
int n,k;
bool judge(int m)
{
	int count0,count1;
	for(int i=1;i<=n;i++)
	{
		int j=i+m-1;
		if(j>n) break;//这里一定要判断,因为s数组开的比较大,后边默认为零
		count1=s[j]-s[i-1];
		count0=m-count1;
		if(min(count1,count0)<=k) return true;
	}
	return false;
}
int main( )
{
	cin>>n>>k;
	l=1; r=n;
	s[0]=0;
	for(int i=1;i<=n;i++)//10101
	{
		cin>>a[i];
		s[i]=s[i-1]+(a[i]-'0');//
	}
	int mid;
	int ans=1;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(judge(mid))
		{
			l=mid+1;
			ans=mid;
		}
		else 
		r=mid-1;
	}
	cout<<ans<<endl;
	return 0;
 } 

eli和字符串
题解:设置一个数组用来存每个字母的个数,再设置一个二维数组,用来存每个字母的位置,第一维表示某个字母,第二维表示当前这个字母的个数

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
char s[200005];
int cnt[30];
int pos[30][200005];
int main( )
{
	int n,k;
	scanf("%d%d",&n,&k);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
	{
		int temp=s[i]-'a';
		cnt[temp]++;
		pos[temp][cnt[temp]]=i;
	}
	int maxx=0x3f3f3f3f;
	for(int i=0;i<26;i++)
	{
		if(cnt[i]>=k)
		for(int j=1;j<=cnt[i]-k+1;j++)//j=1表示从第一次出现这个字母的位置开始
		//cny[j]-k+1表示倒数第二次出现这个字母
		maxx=min(maxx,pos[i][j+k-1]-pos[i][j]+1);
		//pos[i][j+k-1]表示第k次出现这个字母的位置,pos[i][j]表示第一次出现这个字母的位置
	}
	printf("%d\n",maxx==0x3f3f3f3f? -1:maxx);
	return 0;
}
发布了29 篇原创文章 · 获赞 2 · 访问量 584

猜你喜欢

转载自blog.csdn.net/qq_44722533/article/details/104176497