【无标题】

第一题:

题意:

给定一个长度为n的字符串,字符串仅有’?‘1‘’0‘组成;’?‘可以转换为’1’或‘0’;

问是否能将字符串中所有长度为m的字串’1‘和’0‘的个数相同

思路:

因为对于所有的字串都符合1,0个数相同,因此s[i]=s[i+m]=s[i+2*m]=......

所以我们遍历i[1,m],查询s[i],s[i+m],s[i+2*m]...中;

如果既有1,也有0,那么就是无解的;

如果只有1或者(只有0和’?‘),那么s[i]=s[i+m]=..='1';

如果只有0或者(只有1和’?‘),那么s[i]=s[i+m]=...='0';

之后我们只用查询【1,m]中有多少个1,0,? ;判断是否可以构成平衡字串。

const int N = 3e5 + 10, M = 5e2 + 10;
int n,m;
int dp[N];
string s;
void df()
{	
	cin>>n>>m;
	cin>>s;
	s=" "+s;
	for(int i=1;i<=m;i++)
	{	
		 int t1=0,t2=0;
		 for(int j=i;j<=n;j+=m)
		 {
		 	if(s[j]=='1')t1+=1;
			if(s[j]=='0')t2+=1;
		 }
//		 cout<<t1<<"==="<<t2<<endl;
		 if(t1!=0&&t2!=0)
		 {
		 	cout<<"NO"<<endl;
		 	return;
		 }
		 else if(t1!=0)dp[i]=1;
		 else if(t2!=0)dp[i]=0;
		 else//全是? 
		 dp[i]=2;//表示的是两种情况; 
	}
	int p1=0,p2=0;
	for(int i=1;i<=m;i++)
	{
		if(dp[i]==1)p1+=1;
		else if(dp[i]==0)p2+=1; 
	}
//	cout<<p1<<" "<<p2<<endl;
	int tt=abs(p1-p2);
	if(p1==p2)
		cout<<"YES"<<endl;
	else //两个不相同
	{
		int op=m-(p1+p2);//? 
		if(op<tt)
		cout<<"NO"<<endl;
		else
		{
			op-=tt;
			if(op%2)cout<<"NO"<<endl;
			else cout<<"YES"<<endl;
		}
	} 
}

第二题:

题意:

给定一个大小为n非递减的a数组,同时再给一个正整数k;

我们要找出m个大小为n的非递减的b数组,使得a[i]=b[1][i]+b[2][i]+....b[m][i]

对于每个b[i]数组,当中不同元素的个数最多有k个。

求出m的最小值或者不存在。

思路:

才开始没有看清楚题意,以为是b所有的数加起来最多有k种,一直想不出来,选择去看题解,一看发现读错题了。对于这一题,先找出数组中有多少个不同的数,如果种数小于等于k的话,就直接为1.

如果种数大于k的话,在第一个b数组中,我们可以直接消除前k个数,在第二个数组中,前面已经消除的我们要用0来填上,这时剩下(k-1)种,第三个数组中,也是最多可以消除(k-1)种。

另外,我们要注意特判k=1的情况。

因此最小的次数应该是if (n-k)%(k-1)==0,     1+(n-k)/(k-1);

                                    if   (n-k)%(k-1)!=0,        2+(n-k)/(k-1);

​
const int N = 3e5 + 10, M = 5e2 + 10;
int n,k,x,q,p;
int a[N],b[N],c[N];
string s;  
void df()
{	
	cin>>n>>k;
	map<int,int>mp;
	int ans=0;
	int o=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(mp[a[i]]==0)//之前没出现过;
		b[++o]=a[i];
		mp[a[i]]+=1; 
	}
	if(o<=k)
	cout<<1<<endl;
	else 
	{
		if(k==1)//表示不同的个数 
		cout<<"-1"<<endl;
		else 
		{
			ans=1;//第一个数组,现在还剩下o-k个数,但是后续加上的话,只能是(k-1)个,因为有一个是0;
			ans+=(o-k)/(k-1);
			if((o-k)%(k-1))ans++;
			cout<<ans<<endl;
		}
	}
}

​

第三题:

题意:

一道简单题,给定一个n,每次操作都使得n加上;在给定一个m;问最少需要操作多少次可以使得n的每一位上的数加起来的和<=m.

思路:

看完题后,我们会发现在加上次数,使得n发生进位+1,后面的清为0时,操作次数最少

我们保留前面的不用变的数,也就是(前面位数上的数的和再加上1)<=m;

如果第一位上的数就大于m的话,就要加上10^(位数)-n;

在中间的找到最后一位满足前面的和+1<=m的。

void df()
{	
//	cout<<10000000000000-7871987498122<<endl;
	cin>>n>>k;
	int o=0;
	int num=n;
	int ans=0;
	while(num)
	{
		a[++o]=num%10;
		ans+=a[o];
		num/=10;
	}
	if(ans<=k)
	{
		cout<<0<<endl;
		return;
	}
	int op=0;
	for(int i=o;i>=1;i--)
	{
		if((num+a[i]+1)<=k)
			op=i;//可以继续向后面移动 
		else 
			break; 
		num+=a[i];//更新和
	}
//	cout<<op<<endl;
	if(op==0)//第一位上就不满足的
		op=o;
	else op-=1;//保留[op,o]的
	ans=1;
	for(int i=1;i<=op;i++)ans*=10;
	int yy=0;
	int tt=1;
	for(int i=1;i<=op;i++){
		yy+=tt*a[i];
		tt*=10;
	}
//	cout<<ans<<" "<<yy<<endl;
	cout<<ans-yy<<endl;
}

 第四题:

题意:

原本有n个单元格,a[i]=1,表示有平台;a[i]=0,表示没有平台。我们向p的位置上扔一个球,球进行弹跳,p->p+k->p+2*k->....->n;

我们可以进行两种操作,1.在一个空的单元格中添加一个平台,每次操作需要x秒;2.删除第一个单元格,也就是每次只能删除最前面的那个单元格,删除后,后面的补上来,每次操作需要y秒;

思路:

我们删除的只有前面的几个数,后面的我们只能在空的单元格内添加平台,因此,我们先从后到前面来进行遍历,如果当前的数为0时,我们要付出的代价就是a[i]=x+a[i+k];之后我们在枚举我们前面删除的多少个数,计算出每次的时间,最后取最小值即可。

void df()
{	
	//只能删除最前面的; 
	cin>>n>>p>>k;
	cin>>s;
	s=" "+s;
	int y;
	cin>>x>>y;
	for(int i=n;i>=1;i--)
	{
		a[i]=0; 
		if(s[i]=='0')//当前位置上的 
			a[i]=x;
		if(i+k>n)continue; 
		a[i]+=a[i+k];//后面要修改的
	} 
	int ans=1e18;
	for(int i=p;i<=n;i++)//表示我的p从第几个开始//当前是第一个位置 
		ans=min(ans,a[i]+(i-p)*y);//还有p个,剩下的删除; 
	cout<<ans<<endl;
}

第五题:

题意:

给定一个大小为n的数组a[],1<=a[i]<=n;对于每一个长度为k的字段,如果有一个数x,在长度为k的字段中都出现了,找出这些x中最小的一个,如果没有就输出-1,有输出最小值。

 思路:

放了很长时间的一道题,今天终于看着题解,解决了。首先,我们要将数组进行分割,那么,我们就要计算出每个a[i]与相邻的a[i]之间的最大的距离,就表示我们的这个数只有在子段长度大于等于最大距离的时候才可以作为子段中公共出现的数。之后,我们再将每个长度的最小值取出即可。

const int N = 3e5 + 10, M = 5e2 + 10;
int n,k,x,q;
int a[N],b[N],s[N],c[N];
vector<int>v[N];//存的是位置  
void df()
{ 
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		v[i].clear();
		v[i].push_back(0);//在前面加上0; 
	}
		
	int o=0;
	map<int,int>mp;
	for(int i=1;i<=n;i++)
	{
		c[i]=n+5;
		cin>>a[i];
		v[a[i]].push_back(i);//表示位置 
		if(mp[a[i]]==0)
			b[++o]=a[i];
		mp[a[i]]++;
	}
	sort(b+1,b+1+o);
	//记录下每个数所能找到的最小值 
	for(int i=1;i<=o;i++)
	{
		v[b[i]].push_back(n+1);//最后的位置 
		s[b[i]]=0;//原本相差的距离;
		int tt=b[i];
		for(int j=1;j<=mp[b[i]]+1;j++)
		{
//			cout<<v[b[i]][j-1]<<" "<<v[b[i]][j]<<endl; 
			s[b[i]]=max(s[b[i]],v[b[i]][j]-v[b[i]][j-1]);
		} 
			
		//当前的s[b[i]]就是b[i]这个数的最大相隔;
		c[s[b[i]]]=min(c[s[b[i]]],b[i]);
	}
	//记录下最大相隔的位置;
	for(int i=2;i<=n;i++)
		c[i]=min(c[i],c[i-1]);
	for(int i=1;i<n;i++)
	{
		if(c[i]==n+5)
			cout<<"-1"<<" "; 
		else
		cout<<c[i]<<" ";
	}
	cout<<b[1]<<" ";
	cout<<endl;
}

 总结:

一定一定要认真读题,不能太粗糙,要不然受罪的是自己!!!

  • 32
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值