1 条题解

  • 0
    @ 2026-9-24 23:06:58

    题目传送门

    欢迎来博客园阅读!

    题意

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

    思路

    对照样例,不难想到了一点:如果某连续的一段是可消除的,则可以将这一段放到最后再消除。

    这是样例输出:

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

    图示:

    最后两步消除的部分都是连续段。由此或许可以看出一些性质?

    我们考虑递归:

    1. 对于一个可以消除的连续子段,我们将它放在最后消除显然是可行的。
    2. 考虑时光倒流,消除了这个连续子段后将其直接丢掉,这样导致的结果就是会出现新的可以消除的连续子段,我们再将其放在序列中上一次的消除操作的前一次操作,这样就恰好可以满足条件了。

    这么看来,我们的操作序列就是一个栈,同时我们可以在输入的过程中也实现一个栈,以便于我们的删除操作。

    考虑满足什么条件的连续子段可以消除:kk 块白色,11 块黑色。也就是 k+1k+1 块砖之中只有一块黑色或有 kk 块白色。于是考虑维护一个前缀和数组,记录前缀白色砖或黑色砖的块数(我的代码实现中是记录的黑色砖个数)。

    整理一下,在删除的时候需要满足以下几个条件:

    1. 是连续段。
    2. 恰有 11 块黑色砖(或恰有 kk 块白色砖)。

    于是这个题做完了。

    代码实现

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

    完结撒花花!

    • 1

    信息

    ID
    5081
    时间
    1000ms
    内存
    264MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者