結果は、oooxoxで見事Round 1Cへの出場権を獲得した。
とりあえず復習したので、ソースをはっておく。
A. Getting the Digits
0-9の数字をアルファベットで書いたときに、Zは"ZERO"にしか出てこない。
よってZの数を数えれば、0の数がわかる。
0は消えたので、1-9のアルファベット表記を考える。Xは"SIX"にしか出てこない。
よってXの数を数えれば、6の数がわかる。
6は消えたので{1,2,3,4,5,7,8,9}のアルファベット表記を考える。Wは"TWO"にしか出てこない。よってWの数を数えれば、2の数がわかる。
....
という方針で解く。
using namespace std; #define ALL(x) (x).begin(), (x).end() #define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++) #define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++) #define MP(x,y) make_pair(x,y) #define REP(i,n) for(int i=0; i<(int)(n); i++) int freq[128]; int cnt[10]; tuple<string, char, int> vs[] = { {"ZERO", 'Z', 0}, {"SIX", 'X', 6}, {"TWO", 'W', 2}, {"FOUR", 'U', 4}, {"THREE", 'R', 3}, {"FIVE", 'F', 5}, {"ONE", 'O', 1}, {"SEVEN", 'S', 7}, {"EIGHT", 'T', 8}, {"NINE", 'I', 9} }; void solve() { string s; cin >> s; memset(freq, 0, sizeof(freq)); memset(cnt, 0, sizeof(cnt)); for (auto &c: s) freq[c]++; for (auto &v : vs) { string x; char y; int z; tie(x,y,z) = v; cnt[z] = freq[y]; for (auto &c: x) freq[c] -= cnt[z]; } for (int i = 0; i < 10; i++) for (int j = 0; j < cnt[i]; j++) cout << i; cout << endl; } int main() { ios_base::sync_with_stdio(0); int T; cin >> T; REP (i, T) { cerr << "Case #" << i+1 << ": " << endl; cout << "Case #" << i+1 << ": "; solve(); } return 0; }
B. Close Match
2つの数をA, Bとする。Aの桁数をnとする。
A > Bが確定ならば、Aの後続の?は0で埋め、Bの?は9で埋めればよい。
A < Bが確定ならば、Aの後続の?は9で 埋め、Bの?は0で埋めればよい。
k桁目の値(k=0,1,...,nでループ)が決まると、はじめて上記のいずれかが確定するとする。
すると、i < kまではA[i]とB[i]は完全一致でなければならない。
k桁目の値は全列挙。
k+1桁目以降は、0、または、9で埋めればよい。
using namespace std; #define ALL(x) (x).begin(), (x).end() #define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++) #define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++) #define MP(x,y) make_pair(x,y) #define REP(i,n) for(int i=0; i<(int)(n); i++) const long long oo = 1LL<<60; long long diff; string A, B; string ra, rb; void update(const string &a, const string &b) { long long d = abs(stoll(a) - stoll(b)); if (make_tuple(d, a, b) < make_tuple(diff, ra, rb)) { diff = d; ra = a; rb = b; } } void doit(int k, int p, int q, int r, int s) { string a = A; string b = B; int n = A.size(); REP (i, k) { if (a[i] == '?' && b[i] == '?') a[i] = b[i] = '0'; else if (a[i] == '?') a[i] = b[i]; else if (b[i] == '?') b[i] = a[i]; } if (k < n && a[k] == '?') a[k] = '0' + p; if (k < n && b[k] == '?') b[k] = '0' + q; FOR (i, k, n) { if (a[i] == '?') a[i] = r ? '9' : '0'; if (b[i] == '?') b[i] = s ? '9' : '0'; } update(a, b); } void solve() { cin >> A >> B; diff = oo; int n = B.length(); REP (k, n+1) REP (p, 10) REP (q, 10) REP (r, 2) REP (s, 2) { doit(k, p, q, r, s); } cout << ra << " " << rb << endl; } int main() { ios_base::sync_with_stdio(0); int T; cin >> T; REP (i, T) { cerr << "Case #" << i+1 << ": " << endl; cout << "Case #" << i+1 << ": "; solve(); } return 0; }
C. Technobabble
第一ワードと第二ワードをノードと考えてグラフを構築する。
第一ワードvと第二ワードwがtopicを構成するとき、枝(v, w)をはる。
すると、このグラフは二部グラフになることがわかる。
ある枝集合を選ぶと、すべてのノードが少なくとも1つの枝によってリンクされる
<=>
使わなかった枝はfakeとなる
と考えることができる。fakeの最大値が欲しいので、上記の条件を満たす最小の枝集合を選べばいい。これは最小辺カバーであり、
|最小辺カバー| = ノード数 - |最大マッチング|
という関係から、最大マッチングを求めれば計算できる。
using namespace std; #define ALL(x) (x).begin(), (x).end() #define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++) #define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++) #define MP(x,y) make_pair(x,y) #define REP(i,n) for(int i=0; i<(int)(n); i++) class BipartiteMatching { int V; vector<vector<int> >G; vector<int> match; vector<bool> used; bool dfs(int v) { used[v] = true; for (int i = 0; i < (int)G[v].size(); i++) { int u = G[v][i]; int w = match[u]; if (w < 0 || (!used[w] && dfs(w))) { match[v] = u; match[u] = v; return true; } } return false; } public: BipartiteMatching(int v_size) : V(v_size), G(V), match(V), used(V) {} void add_edge(int u, int v) { G[u].push_back(v); G[v].push_back(u); } int count() { int ret = 0; fill(match.begin(), match.end(), -1); for (int v = 0; v < V; v++) { if (match[v] < 0) { fill(used.begin(), used.end(), false); if (dfs(v)) ++ret; } } return ret; } }; int n; string a[1000], b[1000]; map<string, int> s2id(string s[], int n) { map<string, int> ret; REP (i, n) { if (!ret.count(s[i])) { int l = ret.size(); ret[s[i]] = l; } } return ret; } void solve() { cin >> n; REP (i, n) cin >> a[i] >> b[i]; auto aid = s2id(a, n); auto bid = s2id(b, n); int an = aid.size(); int bn = bid.size(); BipartiteMatching bm(an + bn); REP (i, n) bm.add_edge(aid[a[i]], an + bid[b[i]]); int edge_cover = an + bn - bm.count(); cout << n - edge_cover << endl; } int main() { ios_base::sync_with_stdio(0); int T; cin >> T; REP (i, T) { cerr << "Case #" << i+1 << ": " << endl; cout << "Case #" << i+1 << ": "; solve(); } return 0; }
0 件のコメント:
コメントを投稿