2 条题解

  • 0
    @ 2026-8-10 16:28:21

    这题差不多 55 分钟就想出来了,但是有个细节问题调了一会。

    首先要想达成全黑你就得至少保证一行全黑。那么问题转化为对于每一行,将其转为全黑的最小次数。

    那如何将一行的每个白色格子转化为黑色呢?

    考虑只管这一行是不是全黑,对于格子 (i,j)(i,j),它可以由任意一行的第 ii 个格子通过操作覆盖为该格子的颜色。那么只要第 ii 列出现黑色格子,我们就可以在 11 次操作内将其变成黑色。这个记为 aa 操作。

    那如果第 ii 列不存在黑色格子呢?

    考虑对于 1n1 \sim n 行的每一个第 ii 个格子都执行一次上面的查找,不难发现:只要整个网格中存在一个格子为黑色,我们就可以在 11 次操作内使指定的任意一列都能有一个黑色格子。这个记为 bb 操作。

    这样就顺便把无解条件也求出来了。

    而且,对于第 ii 行的每个格子,都只会被第 ii 列有没有黑色格子所影响,所以 bb 操作对整行都有贡献,我们就只需要进行一次 bb 操作了。(我一开始没发现然后每个 aa 操作都执行一次 bb 操作结果居然拿了 9090 分)

    另外一行全黑每次操作会使一列全黑,但是如果这一列本身全黑就不需要操作了,我们需要单独计算全黑的列数量并减去他们。

    好了说完这么多就差不多了。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1010;
    char a[N][N];int b[N],c[N],d[N];
    signed main()
    {
    	int n;cin>>n;
    	for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    	int bk=1;
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[i][j]=='#'){bk=0;break;}
    	if(bk){cout<<-1;return 0;}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)b[j]|=a[i][j]=='#';
    	for(int i=1;i<=n;i++)
    	{
    		int bbk=0;
    		for(int j=1;j<=n;j++)if(a[i][j]!='#')
    		{
    			d[i]++;
    			bbk=1;
    		}
    		if(bbk&&!b[i])d[i]++;
    	}
    	int sum=0,ans=1e18;
    	for(int i=1;i<=n;i++)if(b[i]==n)sum++;
    	for(int i=1;i<=n;i++)
    		ans=min(ans,d[i]+n-sum);
    	cout<<ans<<'\n';
    	return 0;
    }
    • 0
      @ 2026-8-10 10:36:35

      • 1

      信息

      ID
      10089
      时间
      1000ms
      内存
      256MiB
      难度
      9
      标签
      递交数
      13
      已通过
      3
      上传者