ながめも

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

Codeforces Round #637 (Div. 2) - Thanks, Ivan Belonogov!

A. Nastya and Rice

問題概要

一つ重さ x (a-b \le x \le a+b)の粒が N個あり、その和が c-d \le sum \le c+dである場合、粒の重さを決めてsumの範囲におさめられるか。

実装

void solve(){
    int n, a, b, c, d;
    cin >> n >> a >> b >> c >> d;
    int l = c - d;
    int r = c + d;
    if(n*(a+b) < l || r < n*(a-b))cout << "No" << endl;
    else cout << "Yes" << endl;
}

B. Nastya and Door

問題概要

長さ K区間の中で、 a_{i-1} \lt  a_{i} \lt a_{i+1}となるiを峰と呼ぶ。峰の数が最大になる最小の左端 lと、そのときの峰の数の最大値を求めよ。

解説

尺取り?っぽくやるだけだが、本番はdequeを使ってバグらせていた・・・

実装

void solve(){
    ll N, K;
    cin >> N >> K;
    vector<ll> a(N);
    rep(i,N)cin>>a[i];
    a.push_back(a[N-1]);
    //初期化
    ll cnt = 0;
    //0 ~ K-1まで
    for(int i = 1; i <= K-2; i++){
        if(a[i-1] < a[i] && a[i] > a[i+1]){
            cnt++;
        }
    }
    ll ans = cnt;
    ll l = 0;
    for(ll i = K; i < N; i++){
        //i - K が抜ける
        if(a[i-K] < a[i-K+1] && a[i-K+1] > a[i-K+2]){
            cnt--;
        }
        //iが入る
        if(a[i-2] < a[i-1] && a[i-1] > a[i]){
            cnt++;
        }
        if(ans < cnt){
            ans = cnt;
            l = i - K + 1;
        }
    }
    cout << ans + 1 <<" " <<  l + 1 << endl;
}

C. Nastya and Strange Generator

問題概要

難読。説明もするのもキツイが、実験すると、最初に選んだ  iに依存して、そこから右に順に埋まっていくことがわかる。 よって、全ての iについて、

  •  a_i + 1 = a_{i+1}

  •  a_i \gt a_{i+1}

となることがわかる。 こうなっていなかったらNo。

実装

void solve(){
    int N;
    cin >> N;
    vector<int> a(N);
    rep(i,N){
        cin>>a[i];
    }
    rep(i,N-1){
        if(a[i]+1 < a[i+1]){
            cout << "No" << endl;
            return;
        }
    }
    cout << "Yes" << endl;
}

D. Nastya and Scoreboard

問題概要

電光掲示板の初期状態が与えられるので、そこからちょうど K個点灯させて、実現できる最大の数を求めよ。

解説

DPをします。ただ、数の最大を取るようなDPをすると \Theta(N^{2}K)かかるので、まずboolのDPをして、dp[N][K]がtrueかどうかで実現できるかどうかを確認し、実現できるなら、(N, K)から逆に伝播させて遷移の辺を貼り、(0, 0)から貪欲に大きい数字を選んでいけばよい。

実装

//dp[i][j] := i個目までみて、K個使って作れるか
bool dp[2020][2020];
bool back[2020][2020];

int diff(string &x, string &y) {
    int res = 0;
    rep(i, x.size()) {
        if (x[i] == '1' && y[i] == '0')return -1;
        if (x[i] == '0' && y[i] == '1')res++;
    }
    return res;
}

void solve() {
    int N, K;
    cin >> N >> K;
    vector<string> a(N);
    rep(i, N)cin >> a[i];
    string v[] = {
            "1110111", "0010010", "1011101",
            "1011011", "0111010", "1101011",
            "1101111", "1010010", "1111111",
            "1111011"
    };
    rep(i,N+1)rep(j,N+1){
        dp[i][j] = false;
        back[i][j] = false;
    }
    dp[0][0] = true;
    rep(i, N) {
        rep(j, K + 1) {
            if (!dp[i][j])continue;
            for (auto & k : v) {
                int cnt = diff(a[i], k);
                if (cnt == -1)continue;
                if (j + cnt > K)continue;
                dp[i + 1][j + cnt] = true;
            }
        }
    }
    if (!dp[N][K]) {
        cout << -1 << endl;
        return;
    }
    // 逆伝播
    back[N][K] = true;
    for (int i = N; i >= 1; i--) {
        // (i-1, j-cnt) <- (i, j)
        for (int j = 0; j <= K; ++j) {
            if (!back[i][j])continue;
            for (auto &k : v) {
                int cnt = diff(a[i - 1], k);
                if (cnt == -1)continue;
                if (j - cnt < 0)continue;
                if (!dp[i - 1][j - cnt])continue;
                back[i - 1][j - cnt] = true;
            }
        }
    }
    string ans;
    int pre = 0;
    for (int i = 0; i < N; i++) {
        for (int k = 9; k >= 0; k--) {
            int cnt = diff(a[i], v[k]);
            if (cnt == -1)continue;
            if (pre + cnt > K)continue;
            if (back[i + 1][pre + cnt]) {
                ans.push_back(char(k + '0'));
                pre = pre + cnt;
                break;
            }
        }
    }
    cout << ans << endl;
}