还没讲完 先记录一下目前想法
她将灯的亮暗视为灯的两种状态 记为1,0
例如 一串灯的亮暗情况为:
1010,此时我给出一种按灯的方案(1记为按下开关,0相反)
1100,那么最终的结果应该是(1010)^(1100)^(1100 >> 1)^(1100 << 1)
这是因为按下一个开关会对左中右三个点造成影响 而按两下开关相当于没有按开关 这一点和异或(^)很像 1100是对按下的点的影响
1100 << 1是对左边的点的影响
1100 >> 1是对右边的点的影响
因此四者异或和即为最后的开关灯状态
PS 补充一下位运算的优先级 一般来说 位运算都要打括号 alt 那么题目就很简单了 直接枚举第一行的操作 第二行的操作要使第一行满足条件 第三行要使第二行满足条件 以此类推 所有的种类就get了 最后只需判断最后一行是否满足条件

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll a[110], b[110], cur[110], change[110], n, m;
string s[110];

int cal(int x) {
  int cnt = 0;
  for (;x;x >>= 1) {
    if(x & 1) cnt ++;
  }
  return cnt;
}

int deal(ll a[]) {
  int cnt = 0, ans = 2e9;
  for (change[0] = 0;change[0] <= (1 << m) - 1; ++ change[0]) {
    cnt = cal(change[0]);
    cur[0] = a[0] ^ change[0] ^ (change[0] >> 1) ^ ((change[0] << 1) & ((1 << m) - 1));
    /*
    此处注意 左移的值需要去&二进制下相同位数的(1...1) n个1
    目的是为了避免这个多出来的1造成影响
    第一次WA就是因为左移和右移哪个需要这个操作没搞懂
    */
    cur[1] = a[1] ^ change[0];
    for (int i = 1;i < n; ++ i) {
      change[i] = cur[i - 1];
      cnt += cal(change[i]);
      cur[i] = cur[i] ^ change[i] ^ (change[i] >> 1) ^ ((change[i] << 1) & ((1 << m) - 1));
      cur[i + 1] = a[i + 1] ^ change[i];
    }
    if (cur[n - 1] == 0) {
      ans = min(cnt, ans);
    }
  }
  return ans;
}

int main () {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 0;i < n; ++ i) cin >> s[i];
  for (int i = 0;i < n; ++ i) 
    for (int j = 0;j < m; ++ j)
      if (s[i][j] == 'b') a[i] += (1 << j);
      else b[i] += (1 << j);
  if(min(deal(a), deal(b)) > n * m) puts("Impossible");
  else cout << min(deal(a), deal(b));
}

PS:这好像是更优解 一般解是搜索dfs 复杂度会更大