Codeforces 394(#231 Div1) C. Dominoes

問題

10, 11, 00のドミノが合計でn*m個与えられる。
これらを横向きにn*m個に並べる。


それぞれの列ごとにその列の数の和を求める。
この和の最大値が、最小になるようにしたい。最小値を求めよ。


ドミノは回転させることはできるが、縦に使うことはできない。

制約条件

n, m≦10^3

方針

なんか迷走。


10は半分を10, 残りを01と使うとするのが最善。
11, 10, 01をmの倍数の部分は一行に敷き詰めてしまってよい。
mで割った余りの部分が少し考える必要がある。


二列余裕があったら10はできるだけその下に01を置くのが最善。
あとは適当に埋める。という方針で通った。

ソースコード

int sum[2000];
vi ans[1000];
const char *ch[] = {"00", "01", "10", "11"};

int main(){
	int n, m, cnt[4] = {};
	scanf("%d%d", &n, &m);
	rep(i, n) rep(j, m){
		char in[3];
		scanf("%s", in);
		int a = (in[0] - '0') * 2 + in[1] - '0';
		cnt[a]++;
	}
	int s = cnt[1] + cnt[2];
	cnt[1] = s / 2; cnt[2] = s - s / 2;
	
	for(int i = 1; i < 4; i++){
		rep(j, cnt[i] / m) rep(k, m) ans[k].pb(i);
		cnt[i] %= m;
	}
	
	int l = n - ans[0].size(), t = min(cnt[1], cnt[2]);
	if(l > 1) rep(i, t) ans[i].pb(1), ans[i].pb(2);
	cnt[1] -= t; cnt[2] -= t;
	
	for(int i = t; i < m; i++){
		if(cnt[3]) ans[i].pb(3), cnt[3]--;
		else if(cnt[2]) ans[i].pb(2), cnt[2]--;
		else if(cnt[1]) ans[i].pb(1), cnt[1]--;
	}
	while(cnt[1] + cnt[2] + cnt[3] > 0){
		rep(i, m) if(ans[i].size() < n){
			if(cnt[3]) ans[i].pb(3), cnt[3]--;
			else if(cnt[2]) ans[i].pb(2), cnt[2]--;
			else if(cnt[1]) ans[i].pb(1), cnt[1]--;
		}
	}
	
	rep(i, m) while(ans[i].size() < n) ans[i].pb(0);
	rep(i, n) rep(j, m) cout << ch[ans[j][i]] << (j==m-1?"\n":" ");
	
	return 0;
}