【BZOJ3416】Poi2013 Take-out 栈

【BZOJ3416】Poi2013 Take-out

Description

小F喜欢玩一个消除游戏——take-out

保证k+1|n,保证输入数据有解
这是一个单人游戏 游戏者的目标是消除初始时给定的一列砖块,从左往右标号为1到n,若两个砖块标号相差1,则它们相邻 每一块砖块要么是黑的,要么是白的,这列砖块里面白砖块的数量是黑砖块的数量的k倍 游戏者可以通过执行移除操作来消除砖块 一步移除操作会将k个白砖块和1个黑砖块从序列中移除,而这些被移除的砖块原来所在的位置用透明砖块所代替,其它砖块的位置不变 一个移除操作是合法的当且仅当: 在这次移除中,任意两个被移除的砖块之间,没有透明砖块,且恰好移走k个白砖块和1个黑砖块 显然一个砖块不能被移除两次 小F的智商不够……他对着面前密密麻麻的砖块看傻了眼…… 你能帮他玩通关么?
Input 第一行两个数:n,k,意义同题目描述 接下来一行一个由'b'和'c'组成的字符串,长度为n,描述这列砖块 第i个砖块如果是黑色的,那么第i个字符为'c' 否则是白色的,第i个字符为'b' (注:波兰文中b是bialy的首字母,c是czarny的首字母)
Output 输出n/(k+1)行,每行k+1个数,用空格分开,要求递增 第i行表示第i次移除操作移除砖块的位置集合
HINT 2<=n<=1000000,1<=k<n

Sample Input

12 2
ccbcbbbbbbcb

Sample Output

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

题解:一开始以为贪心的从两边取,然后模拟即可,直到我被一大坨特判击倒~

我们将b看成+1,c看成-k,那么每次移除的区间满足左右端点的前缀和相同。所以用栈来维护这个过程,一旦栈顶k+1个元素和=0,则弹栈。最后倒序输出即可。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int maxn=1000010;
int n,m,k,top;
vector<int> p[maxn];
char str[maxn];
int st[maxn];
long long s[maxn];
int main()
{
	scanf("%d%d%s",&n,&k,str+1);
	int i,j;
	for(i=1;i<=n;i++)
	{
		st[++top]=i,s[top]=s[top-1];
		if(str[i]=='b')	s[top]++;
		else	s[top]-=k;
		if(top>=k+1&&s[top-k-1]==s[top])	for(m++,j=0;j<=k;j++)	p[m].push_back(st[top--]);
	}
	for(i=m;i>=1;i--)
	{
		for(j=k;j>=0;j--)	printf("%d ",p[i][j]);
		printf("\n");
	}
}

 

 
posted @ 2017-11-05 17:08  CQzhangyu  阅读(284)  评论(0编辑  收藏  举报