题目链接:https://qoj.ac/contest/531/problem/886
题目大意:给你一个矩阵,每个位置为 $1/2$ ,分别表示恰有一种颜色,和 $\ge 2$ 种颜色。
要求给出三种颜色的染色方案,满足符合上面的矩形,且单个染色是联通的。
我的做法
说来话长,特判掉没有 $2$ ,$n=1$ 和 $m=1$ 的情况。
然后假设每行都有一个 $2$ ,那么两种颜色就够了,奇偶行分别主要染不同的颜色,次要染不同的颜色。(表示 $1/2$ 分别染什么颜色,$1$ 染主要颜色 ,$2$ 主要次要都染)
假设有一个行没有 $2$ ,很自然的想把这一行作为枢纽,用来连接所有的 $0$ ,然后上面主要为 $1$ ,下面主要为 $2$ 。
具体来说,不妨只看单侧,即假设这一行为最后一行:
一种自然的想法是,如果这一列有 $2$ ,那么整一列主要染 $0$ ,次要染 $1$ ,但是这样如果相邻列都有 $2$ ,$1$ 就不连通了,因此会想这种情况下就让下一列主要染 $1$ ,次要染 $0$ 就行了。
综上得到做法,若某列有 $2$ ,先把这一列全部先染个 $0$ ,同时如果下一列相邻格子也有 $2$ ,就把这个格子也染成 $2$ ,然后跳过下一列,染完后,如果一个格子为 $2$ 或者没染过色,就染 $1$ ,对两边分别做一次就行了。
时间复杂度:$O(nm)$ 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
| #include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; const int N = 2e2 + 5; void get_char_array(char *s){ static char ss[N]; cin >> ss; memcpy(s + 1, ss, sizeof(char) * (strlen(ss) + 1)); } int type; char st[N]; int a[N][N], tmp[N][N]; int n, m; bool be[3][N][N]; bool vr[N], vc[N]; bool work1(){ vector<PII> seg; for(int l = 1; l <= m; l++){ if(a[1][l] == 1) continue; int r = l; while(r < m && a[1][r + 1] == 2) r++; seg.push_back({l, r}); l = r; } if(seg.size() >= 3) return 0; for(int j = seg[0].first; j <= seg[0].second; j++) be[2][1][j] = 1; int t = 1; if(seg.size() == 1) t = 0; for(int j = 1; j <= seg[t].second; j++) be[0][1][j] = 1; for(int j = seg[t].first; j <= m; j++) be[1][1][j] = 1; return 1; } void putone(int t){ bool bk = 0; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(a[i][j] == 2){be[t][i][j] = 1; bk = 1; break;} } if(bk) break; } } bool work2(){ putone(2); for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(a[i][j] == 2) be[0][i][j] = be[1][i][j] = 1; else be[i & 1][i][j] = 1; } } return 1; } void rotate(auto f){ for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++) tmp[j][i] = f[i][j]; } for(int i = 1; i <= m; i++){ for(int j = 1; j <= n; j++) f[i][j] = tmp[i][j]; } } int sta[N], top; bool solve(){ cin >> n >> m; bool b2 = 0; for(int i = 1; i <= n; i++){ get_char_array(st); for(int j = 1; j <= m; j++){ a[i][j] = st[j] - '0'; if(a[i][j] == 2){ vr[i] = vc[j] = 1; b2 = 1; } } } if(!b2){ if(n * m <= 2) return 0; int cnt = 0; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++) be[min(cnt, 2)][i][j] = 1, cnt++; } return 1; } if(n == 1) return work1(); if(m == 1){ type = 1; rotate(a); swap(n, m); return work1(); }
int posi = 0; for(int i = 1; i <= n; i++){ if(!vr[i]){posi = i; break;} } if(!posi) return work2(); if(posi == 1) putone(1); if(posi == n) putone(2); for(int j = 1; j <= m; j++) be[0][posi][j] = 1; for(int j = 1; j <= m; j++){ bool bk = 0; for(int i = 1; i < posi; i++){ if(a[i][j] == 2) bk = 1; } if(bk){ for(int i = 1; i < posi; i++){ be[0][i][j] = 1; if(j < m && a[i][j + 1] == 2) be[0][i][j + 1] = 1; } j++; } } for(int j = 1; j <= m; j++){ bool bk = 0; for(int i = posi + 1; i <= n; i++){ if(a[i][j] == 2) bk = 1; } if(bk){ for(int i = posi + 1; i <= n; i++){ be[0][i][j] = 1; if(j < m && a[i][j + 1] == 2) be[0][i][j + 1] = 1; } j++; } } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(a[i][j] == 2 || !be[0][i][j]){ if(i < posi) be[1][i][j] = 1; else be[2][i][j] = 1; } } } return 1; } int main(){ if(!solve()) cout << "impossible\n"; else{ if(type){ for(int t = 0; t <= 2; t++) rotate(be[t]); swap(n, m); } for(int t = 0; t <= 2; t++){ for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(be[t][i][j]) st[j] = t + 'A'; else st[j] = '.'; } cout << st + 1 << "\n"; } cout << "\n"; } } return 0; }
|
官方做法
蚌埠住了,我太菜了,看到第一句话的那一刻起,我感觉赛时构造了一两个小时还没构造出来的我像个小丑一样,构造题真难啊。
注意到,如果我们能给这个矩阵划分成三个独立的连通块,且满足每个点四联通附近都有一个别的连通块的点,那么就显然做完了。
以下是一种可能的方案:

在 $n,m$ 小的时候这种方案可能用不了,特判一下就行了,在此不再赘述。(其实是因为我没细想,因为我觉得最关键的就是上面那句话,以及一种可能的方案,在完成这些后,后面的细节处理就只是时间问题了)