読者です 読者をやめる 読者になる 読者になる

srupのメモ帳

競プロで解いた問題や勉強したことを記録していくメモ帳

SRM 695 div1 easy BearPasswordLexic

問題

問題概要

x = {4, 2, 1, 0}のとき、長さ4の文字列で、その中に、1文字の連続文字列が4つ(b, a, a, a)、2文字の連続文字列が2つ(aa, aa)、3文字の連続文字列が1つ(aaa)、4文字の連続文字列が0つである文字列を出力すればいい。文字列が作れないなら、空文字を出力すればいい。

解法

考察として、例えば、aaaという連続文字列(ex a, b, aa, bb, aaa)があるとき、3連続文字列が1つ、2連続文字列が2つ、1連続文字列が3つとなる。これは、n連続文字列があるとき、n連続文字列が1つ、n-1連続文字列が2つ... 2連続文字列がn-1個、1連続文字列がn個できることになる。よって、文字列を作る条件として必要な連続文字列のなかで、1番長いものから順に作っていけば、それより小さい連続文字列の必要な数も自動的に決まっていく。   実装は、必要ななかで長いものから順に見ていき、必要な数をxから引いていく。その操作をおこなった後に、xのすべての要素が0であればよい。また、文字列の長さもx[0]と一致していなければならない。
答えを出力するときは、辞書順最小なので、必要な連続文字列の長さを長い順に、aの連続列から作り、次にb、次に、aを使った連続文字列を作り、答えとすればいい。

div2は辞書順最小でもなんでもokパターン

mmxsrup.hatenablog.com

ミス

誤読というか読み忘れしてた。
x = {1, 0}みたいな時も、aかbを出力すればよいと思ってたけど、答えとなる文字列はN(=x.size())でなければならないことを忘れていた。

コード

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(n);i++)
const int INF = 1e9;

class BearPasswordAny{
public:
    bool hantei(vector<int> &t){
        rep(i, t.size()){
            if(t[i] != 0) return false;
        }
        return true;
    }

    string findPassword(vector <int> x){

        vector<int> ans;
        int len = x[0];
        while(len > 0){
            for (int i = x.size() - 1; i >= 0; --i){
                if(x[i] > 0){
                    len -= (i + 1);
                    ans.push_back(i + 1);
                    int d = 1;
                    for (int j = i; j >= 0; --j){
                        x[j] -= d;
                        d++;
                    }
                    break;
                }
            }
        }

        string ret = "";
        //x[0]と長さが同じであるかと、すべての長さの連続列を指定された個数作れているかを確認
        if(len == 0 && hantei(x)){
            rep(i, ans.size()){
                rep(j, ans[i]){
                    if(i % 2 == 0){
                        ret += 'a';
                    }else{
                        ret += 'b';
                    }
                }
            }
        }

        //長さが n か見る
        //v = {1, 0}の時などに、ret = "a"となっているので、それをはじく。
        if(ret.size() == x.size()){
            return ret;
        }else{
            ret = "";
            return ret;
        }
    }
};

はじめから、x[0]の値とnが異なれば文字列ができないことがわかる

class BearPasswordAny{
public:
    bool hantei(vector<int> &t){
        rep(i, t.size()){
            if(t[i] != 0) return false;
        }
        return true;
    }

    string findPassword(vector <int> x){

        vector<int> ans;
        int len = x[0];
        //1文字の連続列はどんな文字列を作っても、文字列の長さと同じになる
        if(len != x.size()){
            return "";
        }

        while(len > 0){
            for (int i = x.size() - 1; i >= 0; --i){
                if(x[i] > 0){
                    len -= (i + 1);
                    ans.push_back(i + 1);
                    int d = 1;
                    for (int j = i; j >= 0; --j){
                        x[j] -= d;
                        d++;
                    }
                    break;
                }
            }
        }

        string ret = "";
        //x[0]と長さが同じであるかと、すべての長さの連続列を指定された個数作れているかを確認
        if(len == 0 && hantei(x)){
            rep(i, ans.size()){
                rep(j, ans[i]){
                    if(i % 2 == 0){
                        ret += 'a';
                    }else{
                        ret += 'b';
                    }
                }
            }
        }
        return ret;
    }
};