題目鏈接:[CodeForces 126C]E-reader Display[實現]
題意分析:
給出一張圖,讓你用最短的步驟描繪出這張圖,輸出最短步驟數。
(x,y)代表將區間(x,x)~(x,y)和區間(x,y)~(y,y)的線段0變1,1變0。
解題思路:
從一個點可以染色的區間我們可以發現啊(舉右上方爲例子):這個點能控制的只有它的左平行線和下方垂直線。而且你會發現啊,一個點染色過一次,重新再在這個點染色是浪費的。由上方結論,我們可以得出策略:從右上方開始遍歷,如果這個點要染色,就把這個點給染色了(因爲後期再也沒有點可以給它染色了),然後接着往左,發現,這個點不需要染色,可是被我們的右方點染色了,所以我們就把它染回來。(建議畫個圖,還是蠻好理解的;)
如果單純記錄染色和不染色,這樣更新下去,整個複雜度n^3,所以我們設數組來記錄行和列是否被染色即可,複雜度n^2。
個人感受:
瞎搞啊,沒想到還真是這規律,哈哈哈
具體代碼如下:
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define ll long long
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;
const int INF = 0x7f7f7f7f;
const int MAXN = 2e3 + 111;
char s[MAXN][MAXN];
// a:右上方 b:左下方。舉個例子:ar[i]代表從這個點往左的行是否被染色,其它同
bool ar[MAXN], ac[MAXN], br[MAXN], bc[MAXN];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%s", s[i]);
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = n - 1; j > i; --j) {
if (s[i][j] == '1' && ar[i] + ac[j] != 1) {
ar[i] ^= 1;
ac[j] ^= 1;
++ans;
}
else if (s[i][j] == '0' && ar[i] + ac[j] == 1) {
ar[i] ^= 1;
ac[j] ^= 1;
++ans;
}
}
}
for (int i = n - 1; i >= 0; --i) {
for (int j = 0; j < i; ++j) {
if (s[i][j] == '1' && br[i] + bc[j] != 1) {
br[i] ^= 1;
bc[j] ^= 1;
++ans;
}
else if (s[i][j] == '0' && br[i] + bc[j] == 1) {
br[i] ^= 1;
bc[j] ^= 1;
++ans;
}
}
}
for (int i = 0; i < n; ++i) {
int x = bc[i] + br[i] + ac[i] + ar[i];
if (s[i][i] == '1' && x % 2 == 0) ++ans;
else if (s[i][i] == '0' && x % 2) ++ans;
}
printf("%d\n", ans);
return 0;
}