Codeforces 231 B. Magic, Wizardry and Wonders

問題

n枚のカードがあり、それぞれには1以上l以下の整数一つが書かれている。
このカードに対して以下の操作を繰り返す。


右端の二枚のカードを取り、書かれている数字をa, bとするとき、
二枚のカードをa - bの数字の書かれたカード一枚に置き換える。
(新たなカードの数字は、1以上l以下になっていなくてもよい)


この操作を、カードが一枚になるまで繰り返したとき、最後に残ったカードに書かれた数字はdであった。
元のカードの列として正しいものを、どれか一通り出力せよ。
答えが存在しない場合、-1を出力せよ。
答えが複数ある場合、どれを出力してもよいものとする。

制約条件

2≦n≦100

d ≦10^4

1≦l≦100

方針

最初のカードに書かれていた数字をa1, a2, a3, ..., anとすると、
最後に残るカードの数字dは、d = a1 - a2 + a3 - a4 + … anとなる。


なので、プラスのカードが全部lで、マイナスのカードが全部1のとき、
そのnとlから作れる最大の数字になり、
プラスのカードが全部1で、マイナスのカードが全部lのとき、最小の数字ができる。


この範囲にdがあれば、そのdはちゃんと作れる。そうでない場合は-1を出力する。


そのようなdをどうやって作るかと言うと、まずは全部のカードを1にしておいて、
dと違っている部分だけ直せばいい。


n = 5, d = -4, l = 4の場合(サンプル3)、


最初に1 1 1 1 1を作っておいて、


このままだとdが1なので、あと5を減らしたい。
なので、偶数番目のカードを出来るだけ(減る分まで大きくするか、lまで大きくするかのどちらか)大きくしていく。


dに足りなくて、増やす場合は、奇数番目のカードを増やしていく。

ソースコード

void run()
{
	int n, d, l, ans[100];
	cin >> n >> d >> l;
	
	int b = n / 2, a = n - b;
	//a: プラスのカードの枚数, b: マイナスのカードの枚数

	if(!(a - b * l <= d && d <= a * l - b)){
		cout << -1 << endl;
		return;
	}
	
	rep(i, n) ans[i] = 1, d += i % 2 ? 1 : -1;
	if(d > 0){
		for(int i = 0; i < n; i += 2){
			int p = min(d, l - ans[i]);
			ans[i] += p;
			d -= p;
			if(d <= 0) break;
		}
	}
	else if(d < 0){
		for(int i = 1; i < n; i += 2){
			int p = min(-d, l - ans[i]);
			ans[i] += p;
			d += p;
			if(d >= 0) break;
		}
	}
	rep(i, n) cout << ans[i] << (i == n-1 ?"\n":" ");
}