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;
}

浙公网安备 33010602011771号