有一个大小为n×n的矩阵,由0和1组成。行从上到下编号为1到n,列从左到右编号为1到n。交点(x,y)表示第x行和第y列的单元格。
AquaMoon想将矩阵的所有元素都变为0。在一步操作中,她可以执行以下操作:
Plain Text
选择一个任意的单元格,假设为(i,j),然后翻转(i,j)中的元素,并翻转(x,y)中的所有元素,其中x>i且x−i≥|y−j|。翻转一个值意味着将其改变为相反值:0变为1,1变为0。
帮助AquaMoon确定她需要执行的最少步骤数,以将矩阵的所有元素变为0。我们可以证明答案总是存在。 输入
每个测试包含多个测试用例。第一行包含测试用例的数量t(1≤t≤105)。接下来是测试用例的描述。
每个测试用例的第一行包含一个整数n(2≤n≤3000)。
接下来的n行中的第i行包含一个二进制字符串,只包含字符0和1,长度为n。
保证所有测试用例中n2的总和不超过9000000。 输出
对于每个测试用例,打印最少的步骤数。 示例 输入 复制
3
5
00100
01110
11111
11111
11111
3
100
110
110
6
010101
111101
011110
000000
111010
001110
输出 复制
1
2
15
注意
在第一个测试用例中,我们可以使用以下方案:
Plain Text
在单元格(1,3)上执行操作。
显然,初始矩阵的元素并非全部为0,因此至少需要一次操作。因此,答案为1。
在第二个测试用例中,我们使用以下方案:
Plain Text
- 在单元格(3,3)上执行操作;
- 在单元格(1,1)上执行操作。
可以证明,在0或1步内无法将所有元素转换为0,因此答案正好为2。
题解:
很有意思的一道题,题意也很容易理解,如果操作一个点,向下一个扇形波范围内都会取反,最优肯定是从上往下,如果是1就操作,但是可能会操作很多次,点又有很多,所以很难去确定当前的状态,
我们用结构体来记录一个点的状态
val代表初始的0或1
u代表此时这个点处于多少波的影响下,如果此时这点处于一些波的影响,那么正下方的点也处于那些波的影响
l,r代表每个波除了向下传播之外,还会向左下和右下传播。所以记录每个点会替几个波向左下传播,替几个波向右下传播,然后把这两个属性赋给该点左下/右下的点,同时更新被传播的点的u:既然这些点被一些额外的波影响了,那么影响该点的波的数量自然会增加上这些波的数量。
每个点val +=此时这个点的u,如果%2 == 1要进行操作
- #include<iostream>
- #include<bits/stdc++.h>
- using namespace std;
- #define int long long
- typedef pair<int,int> PII;
- const int N = 5e5 + 10;
- struct node
- {
- int val;
- int u;
- int l,r;
- }a[3004][3004];
- void solve()
- {
- int n;
- cin >> n;
- for(int i = 1;i <= n;i++)
- {
- for(int j = 1;j <= n;j++)
- {
- char c;
- cin >> c;
- a[i][j] = {0};
- a[i][j].val = c - '0';
- }
- }
- int ans = 0;
- for(int i = 1;i <= n;i++)
- {
- for(int j = 1;j <= n;j++)
- {
- a[i][j].val += a[i][j].u;
- if(a[i][j].val%2 == 1)
- {
- ans++;
- a[i][j].u ++;
- a[i][j].l++;
- a[i][j].r++;
- }
-
- a[i + 1][j].u += a[i][j].u;
-
- a[i + 1][j - 1].l += a[i][j].l;
- a[i + 1][j - 1].u += a[i][j].l;
-
- a[i + 1][j + 1].r += a[i][j].r;
- a[i + 1][j + 1].u += a[i][j].r;
- }
- }
- cout << ans <<"\n";
- }
- //111011
- signed main()
- {
- int t = 1;
- ios::sync_with_stdio(0);
- cin.tie(0);
- cout.tie(0);
- cin >> t ;
- while(t--)
- {
- solve();
- }
- }
- //环