1. 程式人生 > 實用技巧 >題解 P3551 【[POI2013]USU-Take-out】

題解 P3551 【[POI2013]USU-Take-out】

題目連結

Solution USU-Take-out

題目大意:給定\(n\)塊磚,黑磚是白磚的\(k\)倍,每次可以拿出\(k + 1\)塊磚,要求其中只有\(1\)塊白磚,且相鄰兩塊磚之間的所有磚都還沒有被拿出來過,求一種可行方案

貪心、棧


分析:首先不考慮相鄰磚之間磚沒有被拿出來的限制,我們可以想到一種貪心的做法

維護一個棧,如果棧頂的\(k + 1\)塊磚裡只有\(1\)塊白磚,彈出\(k + 1\)塊磚,將它們的位置作為一次操作

容易發現,第一次彈的\(k + 1\)塊磚一定是連續的,後面彈的磚雖然在棧裡面連續,但在原序列中兩兩之間的磚都被拿掉了

所以我們只要把彈棧得到操作的順序倒過來,就可以保證操作的合法性了

#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 100;
char str[maxn];
string ans[maxn];
int n,k,cnt,top,tot,stk[maxn];

int main(){
    ios::sync_with_stdio(false);
    cin >> n >> k;
    cin >> (str + 1);
    for(int i = 1;i <= n;i++){
        stk[++top] = i;
        cnt += (str[i] == 'c');
        if(top > k + 1)cnt -= (str[stk[top - k - 1]] == 'c');
        if(cnt == 1 && top >= k + 1){
			ostringstream tmp;
            for(int i = top - k;i <= top;i++)
                tmp << stk[i] << " ";
			ans[++tot] = tmp.str();
            cnt = 0;
            for(int i = top - k - 1;i >= max(top - k - 1 - k,1);i--)cnt += (str[stk[i]] == 'c');
            top -= k + 1;
        }
    }
    for(int i = tot;i >= 1;i--)
        cout << ans[i] << '\n';
    return 0;
}