AtCoder Beginner Contest 117
C - Streamline
https://atcoder.jp/contests/abc117/tasks/abc117_c
方針
座標 を「目的地」と書きます。以下では はソートされているものとします。
まずコマの数が目的地の数以上のとき ( のとき)、初めから全ての目的地にコマを置けばよいので、答えは 0 です。
コマの数より目的地の数のほうが多いときは、コマの移動距離をできるだけ短くしたいので、目的地間の、距離が最も短い区間を移動させることにすればよいです。初手のコマ設置で到達できない目的地は 個ですから、 として を昇順にソートすると、答えは となります。
ソースコード
X の添え字が問題文や上記の方針とずれています。1 - indexedにするために余分な を持つのであれば、 で初期化しないと、 をソートした際に が紛れ込みます。
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int N, M; cin >> N >> M; vector<int> X(M); for(int i=0; i<M; i++) cin >> X[i]; sort(X.begin(), X.end()); // コマの数が目的地の数より多いとき if(N>=M){ cout << 0 << endl; return 0; } vector<int> dX(M-1); for(int i=0; i<M-1; i++){ dX[i] = X[i+1] - X[i]; } sort(dX.begin(), dX.end()); // dX の小さいものから順に M-N 個の和をとる int ans = 0; for(int i=0; i<M-N; i++){ ans += dX[i]; } cout << ans << endl; }
D - XXOR
https://atcoder.jp/contests/abc117/tasks/abc117_d
コンテスト中は話題の嘘解法(上位ビットから順に貪欲)で通しました。以下は公式の解説を参考にしています。
方針
以下で「i ビット目」と書くとき、0 ビット目から始まるとします。
という制限を考えない場合、 を大きくするためには、 XOR の各ビットに立つ 1 の数を出来るだけ多くすればよいです。よって X の i ビット目を、各 の i ビット目に注目して
- の i ビット目が 1 である k の数が、 0 である k の数よりも多いとき、 X の i ビット目は 0
- それ以外のとき、 X の i ビット目は 1
という方針で決めていけば、 を大きくできます。
の条件下では、むやみに X のビットを 1 にすると K を越えてしまうため、上の方針は単純には適用できなくなります。そこで、 を満たすように X の上位ビットを決め打ってしまえば、X の残りのビットは上述の方針で決めていけることを利用します (上位ビットで となれば、下位ビットでこの関係が覆ることはないため)。
ゆえ、 は2進数表記で と表すことができます。同様に と表せます。 となるための条件は、ある が存在して、
(1)
(2)
となることです。 X の上位ビットをこのように決めたとき、残りのビットを当初の方針で決めることで、 を最大にする X と、そのときの の値が求まります。各 i について の最大値を求めれば、それらの中の最大値が所望の値となります。
ソースコード
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int N; ll K; cin >> N >> K; vector<ll> A(N); for(int i=0; i<N; i++) cin >> A[i]; // A の各ビットに 1 がいくつ立っているかを数えておく int nBit = 41; vector<int> cnt(nBit,0); for(int i=0; i<N; i++){ ll a = A[i]; int j = 0; while(a > 0){ if(a%2==1) cnt[j]++; a/=2; j++; } } // K+1 の2進数表記 Kbin を求める ll KK = K + 1; vector<int> Kbin(nBit,0); for(int i=0; i<nBit; i++){ if(KK%2==1) Kbin[i] = 1; KK/=2; } ll ans = 0; for(int i=0; i<nBit; i++){ // X < K+1 となる条件(2): Kbin[i] = 1 if(Kbin[i]==0) continue; // Xbin は X の2進数表記 vector<int> Xbin(nBit,0); // 条件(2): X の i ビット目は 0 Xbin[i] = 0; // 条件(1): i ビット目より上位では X と K+1 は一致する for(int j=i+1; j<nBit; j++){ Xbin[j] = Kbin[j]; } // i ビットより下位では、 // 各 A の j ビット目の 1 の数が N の半分以下のとき // X の j ビット目も 1 にする。 for(int j=0; j<i; j++){ if(cnt[j]<(N+1)/2){ Xbin[j] = 1; } } // 求めた X の2進数表現から X を求める。 ll X = 0; for(int j=0; j<nBit; j++){ if(Xbin[j]==1) X += (ll)1 << j; } // f(X) を計算する ll tmp = 0; for(int j=0; j<N; j++){ tmp += X^A[j]; } ans = max(ans, tmp); } cout << ans << endl; }