有一个大小为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();
}
}
//环