CODE FESTIVAL 2017 Final C - Time Gap (500)
概要
0からNまでの番号が付けられたN+1人について、番号1~Nまでの人の住む都市の時刻は、番号0の人(高橋君)の時刻と比べて差がDiある。
このとき、N+1人の時刻の差の最小値のうち、ありうる最大値を答えよ。
制約
1 ≦ N ≦ 50
0 ≦ Di ≦ 12
方針
番号iの人は高橋君の時刻よりDi時間前かDi時間後かのどちらかであり、各iに対して前か後ろかを全通り試すと答えが出る、がN≦50のときは2^50は10^15くらいなので間に合わない。
効率化を考える。まずは特殊ケース。
高橋君との時刻の差がDiの人が3人いると、必ず2人は同じ時刻になるため答えは0になる。
時刻0の人が高橋君の他にもう1人いる、またはDi = 12の人が2人いても答えは0になる(ちょうど1日違っても、時刻は同じ)。
また、N=1の時はD1自体が答えになる。
これ以外の場合は、Di = jなる人が1人もしくは2人の場合である。
2人の場合は高橋君の時刻を12とするとそれぞれの時刻が12-Di, 12+Diで確定する。
1人の場合は高橋君の前か後ろかをそれぞれ試す。ここまでくると、前か後ろかを試す候補は時刻の12個に収まるので間に合う。
解答
Submission #7053052 - CODE FESTIVAL 2017 Final (Parallel)
#include <bits/stdc++.h> #define rep(i,n) for(int i=(0);i<(n);i++) using namespace std; typedef long long ll; int main() { cin.tie(0); ios::sync_with_stdio(false); int N; cin >> N; vector<int> D(N); rep(i, N) cin >> D[i]; if(N == 1){ cout << D[0] << endl; return 0; } vector<int> c(13, 0); c[0]++; rep(i, N) c[D[i]]++; for(int i = 1; i < 12; i++){ if(c[i] >= 3){ cout << 0 << endl; return 0; } } if(c[12] >= 2 || c[0] >= 2){ cout << 0 << endl; return 0; } vector<int> t; vector<int> d; if(c[0] == 1) t.push_back(12); for(int i = 1; i < 12; i++){ if(c[i] == 2){ t.push_back(12+i); t.push_back(12-i); }else if(c[i] == 1){ d.push_back(i); } } if(c[12] == 1) t.push_back(24); int k = (int) d.size(); int ans = 0; // cout << k << endl; for(int i = 0; i < (1 << k); i++){ for(int j = 0; j < k; j++){ if((i >> j) & 1){ t.push_back(12-d[j]); }else{ t.push_back(12+d[j]); } } sort(t.begin(), t.end()); int s = t[1] - t[0]; int l = (int) t.size(); for(int j = 1; j < l; j++){ s = min(s, t[j] - t[j-1]); } s = min(s, 24 - t[l-1] + t[0]); // cout << i << "," << s << endl; ans = max(ans, s); for(int j = 0; j < k; j++){ if((i >> j) & 1){ t.erase(lower_bound(t.begin(), t.end(), 12-d[j])); }else{ t.erase(lower_bound(t.begin(), t.end(), 12+d[j])); } } } cout << ans << endl; }