[CSP-J 2021] 小熊的果篮朴素做法

 题目链接

https://www.luogu.com.cn/problem/P7912

[题目描述]

小熊的水果店里摆放着一排 n 个水果。

每个水果只可能是苹果或桔子,从左到右依次用正整数 1、2、3、……、n 编号。

连续排在一起的同一种水果称为一个“块”。

小熊要把这一排水果挑到若干个果篮里,具体方法是:每次都把每一个“块”中最左边的水果同时挑出,组成一个果篮。

重复这一操作,直至水果用完。

注意,每次挑完一个果篮后,“块”可能会发生变化。

比如两个苹果“块”之间的唯一桔子被挑走后,两个苹果“块”就变成了一个“块”。

请帮小熊计算每个果篮里包含的水果。

输入格式

输入的第一行包含一个正整数 n,表示水果的数量。

输入的第二行包含 n 个空格分隔的整数,其中第 i个数表示编号为 i的水果的种类,1代表苹果,0 代表桔子。

输出格式

输出若干行。

第 i行表示第 i次挑出的水果组成的果篮。

从小到大排序输出该果篮中所有水果的编号,每两个编号之间用一个空格分隔。

数据范围

对于 10%的数据,n≤5。
对于 30%的数据,n≤1000。
对于 70%的数据,n≤50000。
对于 100%的数据,n≤2×10^5。

解析

看了一眼数据可以直接暴力,用队列来存储原始块的数据。

for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		if(b[i]!=b[i-1])
		{
			zhi[sum]=sum;
			q[sum].push({left,num});
			num=1;left=i;
			sum++;
		}
		else
		{
			num++;
		}
	}
	q[sum].push({left,num});
	zhi[sum]=sum;

 队列的第一个数字存放原始块的第一个节点,第二个数字存放原始块长度    zhi数组代表前方第一个非空块。

用a数组拉储存一个原始块所弹出的个数如果弹出的个数与原始块长度相等,则删除这个原始块,如果整个的合并块的队列为空则删除这个队列,它的指针指向前一个合并块的指针。

a[q[i].front().first]++;
printf("%d ",q[i].front().first+a[q[i].front().first]-1);
ans++;
if(a[q[i].front().first]==q[i].front().second)  q[i].pop(); 
if(q[i].empty()==1)
{
	jilu++;
	zhi[i]=zhi[i-1];
}

如果这个块能与前一个块的指向块合并就将这个块中所有元素入队到前一个块的指向块并清空这个块,将这个块的指针指向更新后的块。

if(b[q[i].front().first]==b[q[zhi[i-1]].front().first])
{
	while(q[i].empty()!=1)
	{
		q[zhi[i-1]].push(q[i].front());
		q[i].pop();
	}
	zhi[i]=zhi[i-1];
	jilu++;//合并到之前的块相当于删除了一个块,所以记录删除的总块数+1
}

而前面有空块,当前块不能与前一个指针指向块合并,则将当前块转移到前一个指针指向块的下一个块中,并更新当前块的指向。

if(zhi[i-1]+1!=i)
{
	zhi[i-1]++;
	while(q[i].empty()!=1)
    {
		q[zhi[i-1]].push(q[i].front());
		q[i].pop();
	}
	zhi[i]=zhi[i-1];
	zhi[zhi[i-1]]=zhi[i-1];
}

将块的总数更新。

sum-=jilu;

讲到这里暴力代码就成形了,双手奉上。

AC代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
queue<PII> q[200001];
int a[200001],b[200001],zhi[200001];
int main()
{
	int n,sum=0,left=0,num=0,ans=0;
	scanf("%d",&n);
	b[0]=-1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		if(b[i]!=b[i-1])
		{
			zhi[sum]=sum;
			q[sum].push({left,num});
			num=1;left=i;
			sum++;
		}
		else
		{
			num++;
		}
	}
	q[sum].push({left,num});
	zhi[sum]=sum;
	while(1)
	{
		int jilu=0;
		if(ans==n)  return 0;
		for(int i=1;i<=sum;i++)
		{
			a[q[i].front().first]++;
			printf("%d ",q[i].front().first+a[q[i].front().first]-1);
			ans++;
			if(a[q[i].front().first]==q[i].front().second)  q[i].pop(); 
			if(q[i].empty()==1)
			{
				jilu++;
				zhi[i]=zhi[i-1];
			}
			else
			{
				if(b[q[i].front().first]==b[q[zhi[i-1]].front().first])//判断这个块能否与前一个指向块合并
				{
					while(q[i].empty()!=1)
					{
						q[zhi[i-1]].push(q[i].front());
				 		q[i].pop();
					}
					zhi[i]=zhi[i-1];
					jilu++;
				}
				else
				{
					if(zhi[i-1]+1!=i)
					{
						zhi[i-1]++;
						while(q[i].empty()!=1)
						{
							q[zhi[i-1]].push(q[i].front());
							q[i].pop();
						}
						zhi[i]=zhi[i-1];
						zhi[zhi[i-1]]=zhi[i-1];
					}
				}
			}
		}
		sum-=jilu;
		printf("\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值