题解:P3551 [POI 2013] USU-Take-out
Circle_Table · · 题解
题目传送门
欢迎来博客园阅读!
题意
每次消除
k+1 个砖,其中k 块白色,1 块黑色,并且这k+1 块砖从开始到结束,中间不能路过已经消除过的砖。
思路
对照样例,不难想到了一点:如果某连续的一段是可消除的,则可以将这一段放到最后再消除。
这是样例输出:
1 8 12
2 6 7
3 4 5
9 10 11
图示:
最后两步消除的部分都是连续段。由此或许可以看出一些性质?
我们考虑递归:
- 对于一个可以消除的连续子段,我们将它放在最后消除显然是可行的。
- 考虑时光倒流,消除了这个连续子段后将其直接丢掉,这样导致的结果就是会出现新的可以消除的连续子段,我们再将其放在序列中上一次的消除操作的前一次操作,这样就恰好可以满足条件了。
这么看来,我们的操作序列就是一个栈,同时我们可以在输入的过程中也实现一个栈,以便于我们的删除操作。
考虑满足什么条件的连续子段可以消除:
整理一下,在删除的时候需要满足以下几个条件:
- 是连续段。
- 恰有
1 块黑色砖(或恰有k 块白色砖)。
于是这个题做完了。
代码实现
#include <bits/stdc++.h>
#define loop(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define rloop(i,a,b) for(int i=(a);i>=(int)(b);i--)
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int n,k,sum[N];
char c;
stack<int>st,ans;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>k;
loop(i,1,n){
cin>>c;
st.push(i);
int s=st.size();
sum[s]=sum[s-1]+(int)(c=='c');
if(s>=k+1&&sum[s]-sum[s-k-1]==1){
rloop(j,s,s-k)ans.push(st.top()),st.pop();
}
}
int T=0;
while(!ans.empty()){
cout<<ans.top()<<' ';
ans.pop();
T=(T+1)%(k+1);
if(!T)cout<<'\n';
}
return 0;
}
完结撒花花!