2 条题解

  • 1
    @ 2026-8-7 9:21:24

    第一次场切绿题,发片题解庆祝一下,

    嘶,我的思路怎么和题解一样......

    题意

    简单来说就是给你一个nnn*n的矩阵,你可以在某一列或某一行刷上1122(颜色会被覆盖,往后用笔触代表这个意思),给出一种可以从白墙刷成目标矩阵的方案,没有方案输出1-1

    大体思路

    首先想要正着推肯定是做不出来的,所以考虑倒推,由题意得,我们可以在每找到笔触时就记录并将这一行或这一列删去(赋值为1-1),因为这一笔会覆盖原来的笔画,所以去掉后并不会太影响答案

    实现

    首先注意删去一个笔触后,画布上也会少一行或者一列,再开一个hh代表还剩下的行数,ll代表还剩下的列数,每找到一个笔触,对应hh--ll--,接下来的寻找就找一行中一个颜色是否与现在的ll相等,一列中一个颜色是否与现在的hh相等

    然后考虑时间复杂度,如果我们纯按照以上思路就大概是O(4n3)O(4*n^3),据DYZDYZ的评测记录会TLETLE四个点.....

    所以我们要优化掉一点,就可以开两个数组ch[i][j]ch[i][j]代表第ii行第jj种颜色的数量(j=1,2j=1,2,因为画00相当于没画)

    同理,cl[i][j]cl[i][j]代表第ii列第jj种颜色的数量,按照上面思路模拟即可,时间大概为O(2n3)O(2*n^3)

    细节

    我们这个思路再判断1-1是有一个细节:

    我们是默认不算00,因为画00等于白画,所以有00存在的点始终没有删去,但00是初始颜色,不能导致结果为1-1,所以当找不到笔触时,还要把矩阵遍历一遍,当有点的颜色不为010或-1时才输出1-1

    还有,我们用的是倒推法,所以输出时记得从头到尾输出

    #include<bits/stdc++.h>
    using namespace std;
    struct node{int x,y,z;}k[4010];
    int n,id=0,a[2010][2010],ch[2010][5],cl[2010][5];
    bool vl[2010],vh[2010];
    int main()
    {
    	scanf("%d",&n);
    	int h=n,l=n;
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
    	{
    		vh[i]=vl[j]=1;
    		scanf("%d",&a[i][j]);
    		ch[i][a[i][j]]++;cl[j][a[i][j]]++;
    	}
    	while(h&&l)
    	{
    		bool f=0;
    		for(int i=1;i<=n;i++)if(vh[i])
    		{
    			for(int j=1;j<=2;j++)if(ch[i][j]==l)
    			{
    				vh[i]=0;
    				k[++id]={1,i,j};
    				f=1;
    				for(int p=1;p<=n;p++)
    				{
    					cl[p][j]--;
    					a[i][p]=-1;
    				}
    				h--;
    			}
    		}
    		if(!h)break;
    		for(int i=1;i<=n;i++)if(vl[i])
    		{
    			for(int j=1;j<=2;j++)if(cl[i][j]==h)
    			{
    				vl[i]=0;
    				k[++id]={2,i,j};
    				f=1;
    				for(int p=1;p<=n;p++)
    				{
    					ch[p][j]--;
    					a[p][i]=-1;
    				}
    				l--;
    			}
    		}
    		if(!f)
    		{
    			for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
    			{
    				if(a[i][j]>0){puts("-1");return 0;}
    			}
    			break;
    		}
    	}
    	printf("%d\n",id);
    	for(int i=id;i;i--)printf("%d %d %d\n",k[i].x,k[i].y,k[i].z);
    	return 0;
    }
    

    tipZJYZJYkk结构体只开了20002000,竟然是WAWA不是RERE

    • 0
      @ 2026-8-5 10:22:42

      解题思路

      首先看完题目,然后发现很难,接着开始写代码,最后一片青青草原。

      考虑倒着思考。最后一次操作一定会让某一行/列全部为 11 或者全部为 22,那么我们每一次只需要删除全为 11 或者全为 22 的行/列,一直到不能操作,然后判断整个地图是否全是 00 即可。

      如果我们直接暴力删除其实是不好模拟的,所以我们用两个变量来表示地图剩下的行数、列数,然后将删除的行/列全部赋值为 1-1,代表当前点不可用,最后统计的时候判断是否全是 1,0-1,0 即可。

      CODE:

      #include <bits/stdc++.h>
      using namespace std;
      #define int long long
      int a[2010][2010], h[2010][10], l[2010][10];
      struct node {
      	int a, b, c;
      };
      bool vish[2010], visl[2010];
      vector<node> v;
      signed main() {
      	ios::sync_with_stdio(false);
      	ios_base::sync_with_stdio(false);
      	cin.tie(0), cout.tie(0);
      	int n;
      	cin >> n;
      	int hh = n, ll = n;
      	for (int i = 1; i <= n; i++) {
      		vish[i] = visl[i] = 1;
      		for (int j = 1; j <= n; j++) {
      			cin >> a[i][j];
      			h[i][a[i][j]]++;
      			l[j][a[i][j]]++;
      		}
      	}
      	while (hh && ll) {
      		bool flag = false;
      		for (int i = 1; i <= n; i++) {
      			if (vish[i]) {
      				for (int j = 1; j <= 2; j++) {
      					if (h[i][j] == ll) {
      						vish[i] = 0;
      						v.push_back({1, i, j});
      						flag = true;
      						for (int k = 1; k <= n; k++) {
      							l[k][j]--;
      							a[i][k] = -1;
      						}
      						hh--;
      					}
      				}
      			}
      		}
      		if (!hh) {
      			break;
      		}
      		for (int i = 1; i <= n; i++) {
      			if (visl[i]) {
      				for (int j = 1; j <= 2; j++) {
      					if (l[i][j] == hh) {
      						visl[i] = 0;
      						flag = true;
      						v.push_back({2, i, j});
      						for (int k = 1; k <= n; k++) {
      							a[k][i] = -1;
      							h[k][j]--;
      						}
      						ll--;
      					}
      				}
      			}
      		}
      		if (!flag) {
      			for (int i = 1; i <= n; i++) {
      				for (int j = 1; j <= n; j++) {
      					if (a[i][j] > 0) {
      						cout << "-1\n";
      						return 0;
      					}
      				}
      			}
      			break;
      		}
      	}
      	cout << v.size() << "\n";
      	for (int i = v.size() - 1; i >= 0; i--) {
      		cout << v[i].a << ' ' << v[i].b << ' ' << v[i].c << "\n";
      	}
      	return 0;
      }
      
      • 1

      信息

      ID
      12552
      时间
      1000ms
      内存
      256MiB
      难度
      7
      标签
      递交数
      70
      已通过
      15
      上传者