CSP历年复赛题-P7912 [CSP-J 2021] 小熊的果篮
原题链接:https://www.luogu.com.cn/problem/P7912
题意解读:连在一起的相同水果形成“块”,每一轮从每一块中挑第一个放入篮子,输出每轮挑的水果的编号。
解题思路:
本题要解决几个问题:
1、将水果分块
2、从块中取出第一个水果
3、将剩下的块进行合并,再重复从每一块取出第一个水果
要尽可能减少数据规模,就得在分块上下功夫,对于一个分块的每一个水果,不用存储所有的水果编号,只需要一个结构体,存储起始编号、结束编号,以及标识哪一种水果
struct node //块
{
int l, r; //该块水果的起始、结束编号
int value; //该块水果的种类,1:苹果 0:桔子
};
然后,将分块构建之后用queue保存和处理,每一轮取出每一块,已经取出的水果用一个数组flag[]来标记,然后将node.l增加到一个没有删除的编号
如果分块一个水果都没有,则要将该分块从queue中移除
如此取完一轮水果之后,再对所有分块进行合并,为了便于处理,可以定一个两个queue(q1,q2),第一轮从q1分块取水果之后可以将所有分块push进q2,再对q2处理分块合并,然后结果又存入q1。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n;
int a[N];
struct node //块
{
int l, r; //该块水果的起始、结束编号
int value; //该块水果的种类,1:苹果 0:桔子
};
bool flag[N]; //flag[i]=1表示i编号的水果已经被删除
queue<node> q1, q2;
int main()
{
cin >> n;
int x;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++)
{
node nd;
nd.value = a[i];
nd.l = nd.r = i;
int j;
for(j = i + 1; a[j] == a[j-1] && j <= n; j++)
{
nd.r = j;
}
q1.push(nd);
i = j - 1;
}
int cnt = n;
while(q1.size())
{
while(q1.size())
{
cout << q1.front().l << " "; //输出块中第一个水果编号
flag[q1.front().l] = 1; //标记删除
cnt--;
while(flag[q1.front().l]) //将块的开始编号增加到第一个没有被删除的编号
{
q1.front().l++;
}
if(q1.front().l > q1.front().r) q1.pop();//如果该块编号为空,则移除整个块
else
{
q2.push(q1.front()); //把该块加入q2,待下次使用,队首出队
q1.pop();
}
}
cout << endl;
//对q2进行块合并,合并后的块放回q1
while(q2.size())
{
node x = q2.front(); //取第一个块
q2.pop();
while(q2.size()) //找若干与第一个块相同的块,进行合并
{
node y = q2.front();
if(y.value == x.value) //与前一个块相同则合并
{
x.r = y.r;
q2.pop();
}
else //与前一个块不同,则跳出开始合并下一系列块
{
break;
}
}
q1.push(x);
}
}
}