D. Matrix Cascade(结构体记录前面对后面的影响)

Problem - D - Codeforces

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值