首页 > 其他分享 >【题解】CF1720C

【题解】CF1720C

时间:2022-08-19 10:55:11浏览次数:69  
标签:操作数 CF1720C int 题解 矩阵 这时候 个数 &&

题意简述

给你一个 01 矩阵,每一次你可以在这个矩阵中找到一个 \(L\) 型,将它全部变成 0。\(L\) 型的定义是在一个 \(2*2\) 矩阵中,除开一个角之外的图形,其中必须包含至少一个 1。

现在需要你找到将整个矩阵变成 1 的最大操作数。

题目分析

由于 L 型是在一个 2*2 的矩阵中,所以我们不妨从这里开始分析。

1. 如果矩阵没有 0

1 1
1 1

这种情况会有 4 个 1。

显然,第一次操作至少会让三个 1 变成 0,然后转到情况 4,这时候最大操作数是 2

此时,操作数 = 1 的个数 -2。

2. 如果矩阵只有一个 0

0 1
1 1

其中的一种情况是上面这样的,这时候会有 3 个 1。

同样的,第一次操作至少会让两个 1 变成 0,然后转到情况 4,这时候最大的操作数是 2

此时,操作数 = 1 的个数 -1。

3. 如果矩阵只有两个 0

0 1 | 0 0
1 0 | 1 1

其中有两种情况如上图,这时候会有 2 个 1。

这时候第一次操作可以只改变一个 1,接着转到情况 4,最大的操作数是 2

此时,操作数 = 1 的个数。

4. 如果矩阵只有三个 0

0 0
0 1

其中一种情况如上,这时候有 1 个 1.

这时候只能改变一个 1,操作数也就是 1。同时显然,矩阵中没有 1 是操作数是 0,这里便不做分类讨论。

此时,操作数 = 1 的个数。

根据上面的分析,我们可以大胆猜想,设 1 的个数为 x,0 的个数为 y,操作数为 ans,则在 2*2 矩阵中:

\(\begin{cases} ans &= x-2 &(y=0) \\ ans &= x-1 &(y=1) \\ ans &=x &(y\ge2) \end{cases}\)

我们尝试将结论推广到普通矩阵中。

没有 0 的情况显然和之前一样。

而这时候就不是只有 1 个 0 的情况,而是在一个 2*2 矩阵中只有 1 个 0。

同样,至少有 2 个 0 的情况也需要转移到在 2*2 矩阵中至少有 2 个 0。

这样我们只要求出 1 的个数并且判断在 2*2 矩阵中有没有至少两个 0 即可。

为什么这种思路是正确的?

一个任意的 n*m 矩阵(\(n,m\ge2\)),都会包含若干个 2*2 的矩阵,即使矩阵可能会重叠。

如果其中有一个矩阵有大于 1 个的 0,就可以从这里开始操作,扩展到每个 2*2 矩阵都有大于 1 个的 0,情况简化成最开始分析中的第三种情况。否则就只能按照第二种情况来扩展。

#include<bits/stdc++.h>
using namespace std;
const int N=5e2+5;
int n,m;
int a[N][N];

signed main(){
	ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--){
		cin>>n>>m;
		int suma=0,sumb=0;//suma是0的个数,sumb是1的个数。其实只记录其中的一个也可以 
		bool f=false;
		for(int i=1;i<=n;i++){
			string s;
			cin>>s;
			for(int j=0;j<m;j++) a[i][j+1]=s[j]-'0';
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(a[i][j]==0){
					suma++;
					//下面判断2*2矩阵中有两个0的情况,注意判断数组越界,用循环也可以 
					if((i+1<=n&&a[i+1][j]==0)||(i-1>=1&&a[i-1][j]==0)||(j-1>=1&&a[i][j-1]==0)||(j+1<=m&&a[i][j+1]==0)) f=true;//两个0是相邻的 
					else if((i+1<=n&&j+1<=m&&a[i+1][j+1]==0)||(i-1>=1&&j-1>=1&&a[i-1][j-1]==0)||(i+1<=n&&j-1>=1&&a[i+1][j-1]==0)||(i-1>=1&&j+1<=m&&a[i-1][j+1]==0)) f=true;//两个0称对角 
				}
				else sumb++;
			}
		}
		if(suma==0) cout<<sumb-2<<"\n";//都是1 
		else if(sumb==0) cout<<"0\n";//都是0 
		else if(f==false) cout<<sumb-1<<"\n";//所有2*2矩阵中都只有一个0 
		else cout<<sumb<<"\n";//任意2*2矩阵中有至少两个0 
	}
	return 0;
}

标签:操作数,CF1720C,int,题解,矩阵,这时候,个数,&&
From: https://www.cnblogs.com/Arcka/p/16601264.html

相关文章

  • QT“程序异常结束”问题解决
    今天用QT写个小程序,出现了一个小问题,就是程序编译通过了,也能运行,但是有一个按键按下后程序就会异常结束。解决办法:由于文件中有多个类,而使用某个类的函数时,存在对象只声......
  • P1967 [NOIP2013 提高组] 货车运输 题解
    题目描述A国有\(n\)座城市,编号从\(1\)到\(n\),城市之间有\(m\)条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有\(q\)辆货车在运输货物,司机们想知道......
  • 题解P2143 [JSOI2010] 巨额奖金
    题意就是让你求有多少种最小生成树生成树用kruskal求就好了我们考虑用dfs中用乘法原理去计数#include<bits/stdc++.h>#defineN1000100usingnamespacestd;ty......
  • ARC097E题解
    感觉挺一眼的啊?众所周知如果序列\(i\)要通过相邻两项交换变成\(p_i\),那么交换次数就是\(\sum_{i<j}[p_i>p_j]\),或者说线段\((i,p_i)\)相交的对数。于是一个很naiv......
  • 【题解】 洛谷P3694 邦邦的大合唱站队
    发现尽管\(n\)比较大,但\(m\)非常小,于是考虑状压。记\(dp_{i}\)表示满足条件的乐队集合为\(i\)时的最小出队人数,\(dp_i=\min\{dp_{i\\xor\\1<<k}\}+w_{i\\xo......
  • [CF1450F] The Struggling Contestant 题解
    \(\mathtt{Link}\)CF1450FTheStrugglingContestant-洛谷|计算机科学教育新生态(luogu.com.cn)\(\mathtt{Description}\)\(T\)组数据。一共有\(n\)道题,题号......
  • P5080 Tweetuzki 爱序列 题解
    题目传送门更好地阅读体验题目大意Tweetuzki有一个长度为\(n\)的序列\(a_1,a_2,\cdots,a_n\)。他希望找出一个最大的\(k\),满足在原序列中存在一些数\(b_1,b......
  • IOI 2022 简要题解
    考前写题解增加RP。D1T1:考虑按照列DP。对于每一列选择的鱼的区间进行决策。每列中被选择的y坐标最大的鱼,需要被左面或右面覆盖。假设我们决策好了前i列的方案,考虑第i列......
  • [题解] HDU 5115 Dire Wolf 区间DP
    考虑先枚举所有的物品中最后拿走的,这样就分成了2个子问题,即先拿完左边的,再拿完右边的,最后拿选出的那个。令dp(i,j)表示拿完[i,j]所有物品的最小代价。你可能会说,我们拿[i,j......
  • 题解 CF1575D【Divisible by Twenty-Five】
    值域非常小,其中只有\(4\times10^6\)个数是\(25\)的倍数,因此可以暴力枚举所有位数正确的\(25\)的倍数,然后检查是否合法。检查方法就是枚举每一位,如果是数字就必须一......