Official

C - X drawing Editorial by mechanicalpenciI


まず、1つ目の操作、

  • \(\max(1-A,1-B)\leq k\leq \min(N-A,N-B)\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

で塗られるマスについて考えます。 これを愚直にシミュレーションしようとすると塗られるマスが最大 \(10^{18}\) 個もあることになり、これは時間制限に間に合いません。そこで、この条件を言いかえることを考えます。 まず、これは、

  • \(1-A\leq k \leq N-A\) かつ \(1-B \leq k \leq N-B\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

と同値であり、すなわち、

  • \(1\leq A+k \leq N\) かつ \(1 \leq B+k \leq N\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

と言い換えられます。 実際に知りたいのは \(P\leq i \leq Q\), \(R\leq j \leq S\) の範囲であり、 \(1\leq P\leq Q \leq N\), \(1\leq R\leq S \leq N\) より、この操作を

  • \(P\leq A+k \leq Q\) かつ \(R \leq B+k \leq S\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

と書き換えても答えは変わりません。これを先の議論と逆の順番で戻して、

  • \(\max(P-A,R-B)\leq k\leq \min(Q-A,S-B)\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

とすることができます。 \(2\) つめの操作についても同様に、

  • \(\max(1-A,B-N)\leq k\leq \min(N-A,B-1)\) をみたす全ての整数 \(k\) について、\((A+k,B-k)\) を黒く塗る。

を、

  • \(\max(P-A,B-S)\leq k\leq \min(Q-A,B-R)\) をみたす全ての整数 \(k\) について、\((A+k,B-k)\) を黒く塗る。

と書き換えられます。 これをシミュレーションで行う事を考えます。 それぞれの操作は高々 \(\min(Q-P+1,S-R+1)\) 回しか行われず、 これは明らかに \(3\times 10^5\) 以下です。(実際は より厳しく、\([\sqrt{300000}]=547\) 回以下と評価できます。 )

よってこのシミュレーションは時間内に行う事ができ、この問題を解く事が出来ました。c++ などで 、シミュレーションしたい範囲を固定長二次元配列等で持つと \(300000\times 300000\) だけ必要になり、メモリ制限を超えてしまうので注意してください。

別解

\(1\)つめの操作の言いかえ、

  • \(1\leq A+k \leq N\) かつ \(1 \leq B+k \leq N\) をみたす全ての整数 \(k\) について、\((A+k,B+k)\) を黒く塗る。

はさらに、

  • \(1\leq i \leq N\) かつ \(1 \leq j \leq N\) かつ \(i-j=A-B\) をみたす全ての整数の組 \((i,j)\) について、マス \((i,j)\) を黒く塗る。

と同値です。同様に \(2\) つめの操作は、

  • \(1\leq i \leq N\) かつ \(1 \leq j \leq N\) かつ \(i+j=A+B\) をみたす全ての整数の組 \((i,j)\) について、マス \((i,j)\) を黒く塗る。

と同値です。 このことを使うと、\(P\leq i\leq Q\), \(R\leq j\leq S\) をみたす各 \((i,j)\) について、 \(i-j=A-B\) または \(i+j=A+B\) の少なくとも一方をみたすかどうかを調べ、みたすならば # を、みたさないならば . を出力すればよいことが分かります。こちらの方が実装は少し簡単になります。

c++による実装例:

#include <bits/stdc++.h>

using namespace std;

int main(void) {
	long long n, a, b;
	long long p, q, r, s;
	long long x, y;
	string str = "";
	vector<string>ans;

	cin >> n >> a >> b;
	cin >> p >> q >> r >> s;

	for (long long i = 0; i < (s - r + 1); i++)str += '.';
	for (long long i = 0; i < (q - p + 1); i++)ans.push_back(str);


	x = max(p - a, r - b);
	y = min(q - a, s - b);
	for (long long i = x; i <= y; i++)ans[a + i - p][b + i - r] = '#';

	x = max(p - a, b - s);
	y = min(q - a, b - r);
	for (long long i = x; i <= y; i++)ans[a + i - p][b - i - r] = '#';


	for (long long i = 0; i < (q - p + 1); i++)cout << ans[i] << endl;

	return 0;
}

c++による実装例(別解):

#include <bits/stdc++.h>

using namespace std;

int main(void) {
	long long n, a, b;
	long long p, q, r, s;

	cin >> n >> a >> b;
	cin >> p >> q >> r >> s;

	for (long long i = p; i <= q; i++) {
		for (long long j = r; j <= s; j++) {
			if ((i - j) == (a - b))cout << '#';
			else if ((i + j) == (a + b))cout << '#';
			else cout << ".";
		}
		cout << endl;
	}

	return 0;
}

posted:
last update: