AtCoder Beginner Contest 121
C - Energy Drink Collector
https://atcoder.jp/contests/abc121/tasks/abc121_c
方針
安い栄養ドリンクから順番に、
- B 本すべて買っても計 M 本に達しない場合は全部買う
- 一部買えば計 M 本に達するときは、必要なだけ買う
というのを繰り返せば答えが得られます。
ソースコード
#include <bits/stdc++.h> typedef long long ll; using namespace std; int main(){ int N, M; cin >> N >> M; vector<pair<ll,ll>> P(N); for(int i=0; i<N; i++){ cin >> P[i].first >> P[i].second; } // 値段の昇順に並び替える。 sort(P.begin(), P.end()); ll ans = 0; for(int i=0; i<N; i++){ ll A = P[i].first; ll B = P[i].second; if(M>B){ // 全て買っても M 本に満たない場合は全部買う M-=B; ans += A*B; }else{ // 一部だけ買えば計 M 本となる場合 ans += A*M; cout << ans << endl; return 0; } } }
D - XOR World
https://atcoder.jp/contests/abc121/tasks/abc121_d
コンテスト中には解けませんでした。反省ですね。
方針
問題文にある通り、 A, A+1, ……, B を2進数で表したとき、k ビット目の 1 が奇数個である場合は の k ビット目は 1 になり、偶数個の場合は 0 になります。そこで A から B の k ビット目の 1 の個数を、各 k について真面目に求めていく方針をとります。 k の範囲ですが、 ですから、 としておけば十分です。
0 以上 以下の中での k ビット目の 1 の個数、とすると A から B の k ビット目の 1 の個数、となります。よって が求められればこの問題を解くことが出来ます。
まずは 0 から適当な値まで 2 進数で書き出してみます:
0 = 0000 1 = 0001 2 = 0010 3 = 0011 4 = 0100 5 = 0101 6 = 0110 7 = 0111 8 = 1000 9 = 1001 10 = 1010
すると、
- の位:0, 1, 0, 1, 0, 1 ……
- の位:0, 0, 1, 1, 0, 0, 1, 1, ……
- の位:0, 0, 0, 0, 1, 1, 1, 1, ……
と言った具合に、 の位は「0 が 個続いた後に 1 が 個続く」(※) というパターンの繰り返しであることが分かります。
0 から N までの数の k ビット目で、(※) のパターンは 個入っており、このなかに 1 は 個入っています (0 から数えると N は N+1 番目の数であることに注意します)。
また (※) のパターンが丸々入るのが続いた後に、(※)の最初の 文字だけが後ろに続きます。この中に 1 は 個入ります。
以上をまとめて
と求まりました。
例えば、下から 3 ビット目(k=2) の 0 , 1の並びを 0 から N = 22 について書き出してみると、
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1
となっています (0 から 22 までについて並べているので、23個の数字が並びます)。この中に "00001111" というパターンはちょうど 個入っており、その後ろにパターンの最初の 文字である "0000111" が付け加わっています。よって 0 から 22 のなかに、3ビット目が 1 であるようなものの個数は 2*4+3=11 個です。
ソースコード
#include <bits/stdc++.h> typedef long long ll; using namespace std; ll g(ll N, ll k){ ll p = (ll)1 << k; return (N+1)/(2*p)*p + max((ll)0, (N+1)%(2*p) - p); } int main(){ ll A, B; cin >> A >> B; ll ans = 0; ll p = 1; for(ll k=0; k<=50; k++){ // A から B の中の k ビット目の 1 の数 ll cnt = g(B,k) - g(A-1,k); // cnt が奇数のとき // f(A,B) の k ビット目が 1 になる。 if(cnt%2==1) ans+=p; p*=2; } cout << ans << endl; }