[题解]CF1926F Vlad and Avoiding X
非常(断句)好暴力。。。
题意
有一个 \(7 \times 7\) 个网格,每一个格子上都有两种颜色,一种是 B,一种是 W。
现在你可以让一个格子上的颜色经行反转(即 B 变为 W 或 W 变为 B),使得网格上没有一个 X 形的图形的颜色都是 B。
思路
首先通过瞪眼法可以发现答案最多为 \(8\)。
然后你再按照下图重新分析一下,发现蓝色和红色的反转是无关的,并且红色和蓝色反转的次数都最多为 \(4\),因此考虑分别计算。

以下以红色为例,蓝色的计算方式同理。
首先枚举反转次数 \(i\),然后暴力 DFS 去 check。由于我们将红色和蓝色分开了,因此红色点集合的元素是 \(\frac{n}{2}\) 的。
单次 check 的复杂度就是在红色的 \(\frac{n}{2}\) 选出 \(i\) 个数去反转,因此为 \(\Theta(\binom{25}{i} \times \frac{n}{2})\)。总复杂度大约是 \(\Theta(\binom{25}{4} \times n)\)。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 10;
int dx[] = {0,1,1,-1,-1};
int dy[] = {0,1,-1,1,-1};
int arr[N][N];
char s[N][N];
struct point{
int x,y;
};
vector<point> g[2];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline void init(){
for (re int i = 1;i <= 7;i++){
for (re int j = 1;j <= 7;j++) g[(i + j) % 2].push_back({i,j});
}
}
inline bool check(int op){
for (auto x:g[op]){
if (!arr[x.x][x.y]) continue;
int num = 0;
for (re int i = 1;i <= 4;i++){
int tx = x.x + dx[i];
int ty = x.y + dy[i];
if (tx >= 1 && tx <= 7 && ty >= 1 && ty <= 7) num += arr[tx][ty];
}
if (num == 4) return false;
}
return true;
}
inline bool dfs(int u,int res,int op){
if (!res) return check(op);
if (u == g[op].size()) return false;
bool ok = false;
point x = g[op][u];
ok |= dfs(u + 1,res,op);
arr[x.x][x.y] ^= 1;
ok |= dfs(u + 1,res - 1,op);
arr[x.x][x.y] ^= 1;
return ok;
}
inline void solve(){
int ans = 0;
for (re int i = 1;i <= 7;i++){
scanf("%s",s[i] + 1);
for (re int j = 1;j <= 7;j++) arr[i][j] = (s[i][j] == 'B');
}
for (re int i = 0;i <= 4;i++){
if (dfs(0,i,0)){
ans += i;
break;
}
}
for (re int i = 0;i <= 4;i++){
if (dfs(0,i,1)){
ans += i;
break;
}
}
printf("%d\n",ans);
}
int main(){
init();
int T;
T = read();
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号