ながめも

競技プログラミングについて

Codeforces Round #657 (Div. 2) 参加記

A Acacius and String

 \Theta(N^{2})なら、毎回ある一箇所を変更して一個だけかどうかを判定すればよいです。 \Theta(N)は難しそうです。

Div2-Aにしては実装が重いですね。

void solve(){
    int N;
    string S;
    cin >> N >> S;
    string t = "abacaba";
    vector<int> idxes;
    rep(i,N-6){
        string tmp = S.substr(i,7);
        if(tmp == t)continue;
        bool ok = true;
        rep(i,7){
            if(tmp[i] == '?')continue;
            if(tmp[i] != t[i])ok = false;
        }
        if(ok){
            idxes.push_back(i);
        }
    }
    auto f = [&](string T) -> int{
        int sz = T.size();
        int res = 0;
        rep(i,sz-6){
            string tmp = T.substr(i, 7);
            if(tmp == t)res++;
        }
        return res;
    };
    int cnt = f(S);
    if(cnt == 0){
        //変えないといけない
        int start = -1;
        for(auto p: idxes){
            string T = S;
            rep(j,7){
                T[p+j] = t[j];
            }
            int cntt = f(T);
            if(cntt == 1){
                start = p;
                break;
            }
        }
        if(start == -1){
            cout << "No" << endl;
        }
        else{
            cout << "Yes" << endl;
            rep(j,7){
                S[start+j] = t[j];
            }
            rep(i,N){
                if(S[i] == '?')cout << 'd';
                else cout << S[i];
            }
            cout << endl;
        }
    }
    else if(cnt == 1){
        cout << "Yes" << endl;
        rep(i,N){
            if(S[i] == '?')cout << 'd';
            else cout << S[i];
        }
        cout << endl;
    }
    else{
        cout << "No" << endl;
    }
}

B Dubious Cyrpto

 l,r,mが与えられるので、 l \le a,b,c \le rなる整数 a,b,cで、 n \times a + b - c = mを満たすものを求めよ。」という問題。

 aを固定して、 aの倍数を mに近づけて、その余りを bとcの差で表現できるかを判定する。

void solve(){
    ll l, r, m;
    cin >> l >> r >> m;
    for(ll a = l; a <= r; a++){
        if(m >= a){
            ll d = m % a;
            // b > cで幅d持てるかどうか
            if(l + d <= r){
                cout << a << " " << l+d << " " << l << endl;
                return;
            }
            d = ((m+a-1)/a)*a - m;
            if(l + d <= r){
                cout << a << " " << l << " " << l + d << endl;
                return;
            }
        }
        else{
            ll d = a - m;
            // c > bで幅d持てるかどうか
            if(l + d <= r){
                cout << a << " " << l << " " << l+d << endl;
                return;
            }
        }
    }
}

C Choosing flowers

複数取る花は高々 1個です。よって、それを全探索します。取る花の b xとすると、 a_i > b aは全て取ることになります。 xを大きい順に固定していくことで、尺取り法で実装できます。  xが小さくなっていくと aの候補が増えていくからです。

ある花 iを取るとしたとき、必ず a_iも取らないといけません。これは、尺取りで進めている aの範囲に入ってない場合は追加します。

また、コーナーケースとして、複数取る花が 0個の場合があります。

void solve(){
    ll N, M;
    cin >> N >> M;
    vector<ll> a(M), b(M);
    vector<l_l> v;
    rep(i,M){
        cin >> a[i] >> b[i];
        v.emplace_back(b[i], a[i]);
    }
    // aの大きい順に並んでいる
    sort(all(a), greater<>());
    sort(all(v), greater<>());
    ll ans = 0;
    // baseライン
    if(N <= M)rep(i,N)ans += a[i];
    ll sum = 0;
    int idx = 0;//尺取りのindex
    // iのbで残り全部埋めて、b[i] < a[i]花は取る
    rep(i,M){
        // b < aを取る
        ll bb = v[i].first;
        while(idx < M && bb < a[idx]){
            sum += a[idx];
            idx++;
        }
        ll cnt = idx; // 追加個数
        ll tmp = sum;
        ll aa = v[i].second;
        // 尺取りで入っていないので足す
        if(aa <= bb){
            tmp += aa;
            cnt++;
        }
        // 残りは全てbb
        if(N - cnt < 0)continue;
        tmp += (N - cnt) * bb;
        chmax(ans, tmp);
    }
    cout << ans << endl;
}