ABC173自分なりのまとめ
A- Payment
N円を超えるまで1000円ずつ足していけば良いです。
//競技プログラミング用のテンプレート #include <iostream> #include <vector> #include <algorithm> #include <map> #include <queue> #include <string> #include <math.h> #include <stack> #include <limits> #define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i) #define repr(i, n) for(int i = n - 1; i >= 0; i--) using namespace std; //エイリアス using ll = long long int; using p = pair<int, int>; using pl = pair<ll, ll>; using v = vector<int>; using vd = vector<double>; using vs = vector<string>; using vl = vector<ll>; //定数 const int intmax = numeric_limits<int>::max(); const ll llmax = numeric_limits<ll>::max(); const ll mod = 1e9 + 7; const double pi = M_PI; int main() { int n; cin >> n; int pay = 1000; while(pay < n) { pay += 1000; } cout << pay - n << endl; }
B- Judge Status Summary
mapにそれぞれの出現回数を記録しました。
//競技プログラミング用のテンプレート #include <iostream> #include <vector> #include <algorithm> #include <map> #include <queue> #include <string> #include <math.h> #include <stack> #include <limits> #define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i) #define repr(i, n) for(int i = n - 1; i >= 0; i--) using namespace std; //エイリアス using ll = long long int; using p = pair<int, int>; using pl = pair<ll, ll>; using v = vector<int>; using vd = vector<double>; using vs = vector<string>; using vl = vector<ll>; //定数 const int intmax = numeric_limits<int>::max(); const ll llmax = numeric_limits<ll>::max(); const ll mod = 1e9 + 7; const double pi = M_PI; string cand[] = {"AC", "WA", "TLE", "RE"}; int main() { int n; cin >> n; map<string, int> memo; rep(i, n) { string s; cin >> s; memo[s]++; } rep(i, 4) { printf("%s x %d ", cand[i].c_str(), memo[cand[i]]); } }
C- H and V
H + Wビットのbit全探索を行えばよいです。
H,Wともに6以下なので計算量的にも問題ありません。
//競技プログラミング用のテンプレート #include <iostream> #include <vector> #include <algorithm> #include <map> #include <queue> #include <string> #include <math.h> #include <stack> #include <limits> #define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i) #define repr(i, n) for(int i = n - 1; i >= 0; i--) using namespace std; //エイリアス using ll = long long int; using p = pair<int, int>; using pl = pair<ll, ll>; using v = vector<int>; using vd = vector<double>; using vs = vector<string>; using vl = vector<ll>; //定数 const int intmax = numeric_limits<int>::max(); const ll llmax = numeric_limits<ll>::max(); const ll mod = 1e9 + 7; const double pi = M_PI; string grid[6] = {""}; void choose(map<int, int> &memo, int bits, int &comp, int size) { for(int i = 0; i < size; i++) { if (bits & comp) { memo[i] = 1; } comp = comp << 1; } } int count(int h, int w, map<int, int> &row, map<int, int> &col) { int result = 0; for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { if (row.count(i) == 0) continue; if (col.count(j) == 0) continue; if (grid[i][j] == '#') result++; } } return result; } int main() { int h, w, k; cin >> h >> w >> k; rep(i, h) { cin >> grid[i]; } int cand = 0; for(int i = 0; i < pow(2, h + w); i++) { int comp = 1; map<int, int> row; map<int, int> col; choose(row, i, comp, h); choose(col, i, comp, w); int temp = count(h, w, row, col); if (temp == k) cand++; } cout << cand << endl; }
D- Chat in a Circle
結構難しめかな?
最適性の証明が難しかったです。(今もできてるか怪しい)
直感的には思いつきやすいのではないでしょうか
最初にプレイヤーをフレンドリーさの降順にソートします。
その後、それぞれのフレンドリーさを何回心地よさに加えることができるかを考えます。
一番大きいフレンドリーさA{max}は1回しか加えることができません。
これは、心地よさに加えられるフレンドリーさは両脇のうち小さい方だからです。
では、その次に大きいフレンドリーさは何回加えられるでしょうか?
フレンドリーさの降順に到着していくと仮定すると、最大2回加えられることがわかります。
右隣にプレイヤーを到着させた場合と、左隣にプレイヤーを到着させた場合です。
フレンドリーさの降順に到着していくと仮定しているので、右隣と左隣、一回ずつしか加えられません。
この場合、最終的な心地よさの合計は、A{max} + 2 * A_i (i != max)となります。
次に、この到着の仕方が最適であることを証明します。
もしあるフレンドリーさA_iを2回よりも多く心地よさに加えようとすると、プレイヤーiよりもあとに到着するプレイヤーの
フレンドリーさの方が大きい必要があります。
すると、A_iを余分に加えることができたメリットよりも、後に到着したプレイヤーのフレンドリーさを加えられなかったデメリットのほうが
大きくなるため、フレンドリーさの降順に到着するのが最適だとわかります。
//競技プログラミング用のテンプレート #include <iostream> #include <vector> #include <algorithm> #include <map> #include <queue> #include <string> #include <math.h> #include <stack> #include <limits> #define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i) #define repr(i, n) for(int i = n - 1; i >= 0; i--) using namespace std; //エイリアス using ll = long long int; using p = pair<int, int>; using pl = pair<ll, ll>; using v = vector<int>; using vd = vector<double>; using vs = vector<string>; using vl = vector<ll>; //定数 const int intmax = numeric_limits<int>::max(); const ll llmax = numeric_limits<ll>::max(); const ll mod = 1e9 + 7; const double pi = M_PI; int main() { int n; cin >> n; vl a(n, 0); rep(i, n) cin >> a[i]; sort(a.begin(), a.end()); reverse(a.begin(), a.end()); ll sum = a[0]; int arrived = 2; for(int i = 1; i < n && arrived <= n; i++) { if (arrived + 1 <= n) { sum += a[i]; arrived++; } if (arrived + 1 <= n) { sum += a[i]; arrived++; } } cout << sum << endl; }
E- Multiplication 4
コンテスト中には解けなかったけど、D問題よりも考察自体は簡単かも
基本的に、絶対値の降順にk個取ったとき、掛け算の結果がマイナスにならなければそれが解になります。
解がマイナスになった場合は
- 負の数をK個の中から一つ取り除いて、正の数を追加する
- 正の数をK個の中から一つ取り除いて、負の数を追加する
ことで、結果を正にすることができます。
どちらの方法をとったほうが解が大きくなるかは
- R: 先頭からK個取ったときの解
- P1: K個の中から最も小さい正の数
- M1: K個の中から最も絶対値が小さい負の数
- P2: 残った数の中から最も大きい正の数
- M2: 残った数の中から最も絶対値が大きい負の数
とすると
- P1 * P2 < M1 * M2
で比較することができます。
あとは細かい例外を適切に処理していけば解けるはずです。
コードが説明と若干離れているのは目をつぶってください。
//競技プログラミング用のテンプレート #include <iostream> #include <vector> #include <algorithm> #include <map> #include <queue> #include <string> #include <math.h> #include <stack> #include <limits> #define rep(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i) #define repr(i, n) for(int i = n - 1; i >= 0; i--) using namespace std; //エイリアス using ll = long long int; using p = pair<int, int>; using pl = pair<ll, ll>; using v = vector<int>; using vd = vector<double>; using vs = vector<string>; using vl = vector<ll>; //定数 const int intmax = numeric_limits<int>::max(); const ll llmax = numeric_limits<ll>::max(); const ll llmin = numeric_limits<ll>::min(); const ll mod = 1e9 + 7; const double pi = M_PI; ll calc_only(vl &src, int k) { ll ans = 1; for(int i = 0; i < k; i++) { ans *= src[i]; ans %= mod; } return ans; } ll calc_mix_even(vector<pair<ll, int>> &mix, int k) { ll ans = 1; for(int i = 0; i < k; i++) { ans *= mix[i].first; ans %= mod; } return ans; } ll calc_mix_odd_without(vector<pair<ll, int>> &mix, int k, int target) { ll ans = 1; for(int i = 0; i < k; i++) { if (i == target) continue; ans *= mix[i].first; ans %= mod; } return ans; } int get_last_index(vector<pair<ll, int>> &mix, int k, int target) { int last_index = -1; for(int i = 0; i < k; i++) { if(mix[i].second == target) last_index = i; } return last_index; } int get_first_index(vector<pair<ll, int>> &mix, int k, int target) { for(int i = k; i < mix.size(); i++) { if(mix[i].second == target) return i; } return -1; } ll adapt(vector<pair<ll, int>> &mix, int k, int without, int add) { ll ans = calc_mix_odd_without(mix, k, without); ans *= mix[add].first; ans %= mod; return ans; } ll calc_mix_odd(vector<pair<ll, int>> &mix, int k) { ll ans = llmin; int plus_last = get_last_index(mix, k, 1); int minus_last = get_last_index(mix, k, -1); int plus_first = get_first_index(mix, k, 1); int minus_first = get_first_index(mix, k , -1); if (plus_last == -1) { //プラスが<kにそもそも存在しない //マイナスを取り除いてプラスを入れる return adapt(mix, k, minus_last, plus_first); } if (plus_first == -1) { //プラスが>=kに存在しない //プラスを取り除いてマイナスを入れる return adapt(mix, k, plus_last, minus_first); } if (minus_first == -1) { //マイナスが>=kに存在しない //マイナスを取り除いてプラスを入れる return adapt(mix, k, minus_last, plus_first); } ll plus1 = mix[plus_last].first; ll minus1 = mix[minus_last].first; ll plus2 = mix[plus_first].first; ll minus2 = mix[minus_first].first; if (plus1 * plus2 < minus1 * minus2) { //プラスを取り除いてマイナスを入れる return adapt(mix, k, plus_last, minus_first); } else { //マイナスを取り除いてプラスを入れる return adapt(mix, k, minus_last, plus_first); } } ll calc_mix(vector<pair<ll, int>> &mix, int k) { int num_minus_in_k = 0; for(int i = 0; i < k; i++) { if (mix[i].second == -1) num_minus_in_k++; } if (num_minus_in_k % 2 == 0) { return calc_mix_even(mix, k); } if (num_minus_in_k % 2 != 0) { return calc_mix_odd(mix, k); } } int main() { int n, k; cin >> n >> k; vl as(n, 0); vl plus, minus, minusr; vector<pair<ll, int>> abss(n); rep(i, n) { ll a; cin >> a; as[i] = a; if (a < 0) { minus.push_back(a); abss[i] = {abs(a), -1}; }else{ plus.push_back(a); abss[i] = {a, 1}; } } sort(plus.begin(), plus.end()); reverse(plus.begin(), plus.end()); sort(minus.begin(), minus.end()); minusr = minus; reverse(minusr.begin(), minusr.end()); sort(abss.begin(), abss.end()); reverse(abss.begin(), abss.end()); //全部正 if (plus.size() == n) { ll ans = calc_only(plus, k); cout << ans << endl; return 0; } //全部負 if (minus.size() == n) { ll ans = llmin; if (k % 2 == 0) ans = calc_only(minus, k); if (k % 2 != 0) ans = calc_only(minusr, k); if (ans < 0) ans += mod; cout << ans << endl; return 0; } //n == k if (n == k) { ll ans = calc_only(as, k); if (ans < 0) ans += mod; cout << ans << endl; return 0; } //それ以外 ll ans = calc_mix(abss, k); cout << ans << endl; }