mini notes

競技プログラミングの解法メモを残していきます。

CodeThanksFestival 2017

E - Coin Authentication (400)

E - Coin Authentication

概要

インタラクティブ問題。
N個の袋の中にコインが10000枚入っている。
コインの重さは8,\ 9,\ 10,\ 11,\ 12gの5種類であり、同じ袋の中には同じ種類のコインが入っている。
上記のうち9,\ 11gのコインが本物のコインであり、8,\ 10,\ 12gのコインが偽物のコインであるとする。
「各袋から好きな枚数ずつ取り出して合計の重さをはかる」操作を高々10回行い、
それぞれの袋に含まれているコインが本物であるか偽物であるかを特定せよ。

制約

 1 \leq N \leq 50

方針

5袋ずつから1,\ 10,\ 100,\ 1000,\ 10000枚ずつ取り出して重さを測る。
全体の重さから5袋それぞれのコインの種類を特定することが可能。

感想

コインの重さが5種類なので重さを5進数に対応させればよい。
そのため、取り出す枚数は1,\ 5,\ 25,\ 125,\ 625枚でよい。

解答

Submission #3915208 - CODE THANKS FESTIVAL 2017(Parallel)

#include <bits/stdc++.h>
 
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define rep(i,n) FOR(i,0,n)
#define RFOR(i,a,b) for(int i=(a)-1;i>=(b);i--)
#define rrep(i,n) RFOR(i,n,0)
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
 
const int max_n = 53;
int n;
int m;
int ans[max_n];
 
void setAns(int x, ll ret){
	int y = 5 * x;
	rep(i, 5){
		int u = ret % 10;
		// cout << i << " " << ret << endl;
		if(u == 9 || u == 1){
			ans[y] = 1;
		}else if(u == 0 || u == 2 || u == 8){
			ans[y] = 0;
		}else{
			// cout << "error:" << y << " " << ret << endl; 
		}
		ret /= 10;
		if(u % 10 <= 2) ret--;
		y++;
	}
}
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	cin >> n;
	m = (n % 5 == 0 ? n / 5: n / 5 + 1);
	rep(i, m){
		cout << "?";
		rep(j, n){
			cout << " ";
			if(5 * i <= j && j < 5 * (i+1) ){
				cout << pow(10, j % 5);
			}else{
				cout << 0;
			}
		}
		cout << endl;
 
		ll ret;
		cin >> ret;
 
		setAns(i, ret);
	}
 
	cout << "!";
	rep(i, n) cout << " " << ans[i];
	cout << endl;
}