P3551 题解报告

有 n 块砖,其中白色是黑色的 \(k\) 倍,求一个消除序列,满足以下条件:

每次消除 \(k+1\) 个砖,其中 \(k\) 块白色,\(1\) 块黑色,并且这 \(k+1\) 块砖从开始到结束,中间不能路过已经消除过的砖。

解析:

倒退法!

先找连续且只包含一个黑色块的序列,因为在最后时刻只能选择连续的序列。

如样例:

c  c  b  c  b  b  b  b  b  b  c  b
1  2  3  4  5  6  7  8  9  10 11 12

那么在第一个连续且只包含一个黑色块的序列 \([3,5]\) 可以存起来,并把它从原序列删去可得新序列:

c  c  b  b  b  b  b  c  b
1  2  6  7  8  9  10 11 12

如同原来做法删去 2 6 7。

发现了什么——我们通过倒退法跨过正顺序做法的最后要删除的序列,且满足每次消除 \(k+1\) 个砖,其中 \(k\) 块白色,\(1\) 块黑色,并且这 \(k+1\) 块砖从开始到结束,中间不能路过已经消除过的砖。

以上为皆思路,要实现它,可以用到栈:我们将一直将数入栈,如果发现栈内有比 \(k+1\) 多的数且满足这 \(k+1\) 个数只有一块黑色块,那么出栈并存起(倒叙,至于为什么,因为后面要全部倒叙输出),一直到数字全入完栈且出完栈(数据保证有解)。

最后要倒叙输出,至于为什么,因为我们通过倒叙法作出,所得第一个序列其实是最后序列(所以题目其实根本不用按照升序输出,且可能只有这一种输出方式)。

CODE:


#include<bits/stdc++.h>
using namespace std;
char s[10101010];
int sum[10101010],q[10101010],ans[10101010];
int n,k;
int main()
{
	cin>>n>>k;
	cin>>s+1;
	int tot=0,num=0;
	for(int i=1;i<=n;i++)
	{
		tot++;
		q[tot]=i;
		if(s[i]=='c')
		{
			sum[tot]=sum[tot-1]+1;
		}
		else
		{
			sum[tot]=sum[tot-1];
		}
		if(sum[tot]-sum[tot-k-1]==1&&tot>=k+1)
		{
			for(int j=tot;j>tot-k-1;j--)
			{
				ans[++num]=q[j];
			}
			tot=tot-k-1;
		}
	}
	int js=0;
	for(int j=num;j>=1;j--)
	{
		++js;
		cout<<ans[j]<<" ";	
		if(js==3)
		{
			cout<<'\n';
			js=0;	
		}
	}
	return 0;
}
posted @ 2022-02-16 17:32  ㅤSmartBig  阅读(129)  评论(0)    收藏  举报