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: