题意分析:
给出一张图,让你用最短的步骤描绘出这张图,输出最短步骤数。
(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; }