n个灯,每一个灯只有开关两种状态,开始都关着。ios
m个开关,每一个开关对应若干个灯,拉动一下就会使该开关控制的全部灯改变状态。spa
问有多少种不一样的状态。code
考虑把每一个灯抽象成一个二进制位,开是1,关是0,那么当前状态就是一个二进制数。ci
而后拉动开关就至关于给当前状态异或上一个数。get
因而问题转化为求一些数能xor出多少不一样的数。(由于一开始是0,异或0等于不异或)io
考虑创建一个线性基。既然原序列xor能获得的集合与线性基xor能获得的集合相同,那么其大小也是相同的。class
因为线性基异或获得的数一定没有重复的(根据基的定义,有且仅有一种方式获得一个数),那么选或不选线性基里的一个数就会致使获得不一样的数。stream
而每一个数有选和不选两种状态,因此答案是\(2^{size}\)(\(size\)是线性基内元素个数,即线性基大小)二进制
注意溢出。集合
#include <iostream> using namespace std; char read() { char c; do { c = getchar(); } while (c == ' ' || c == '\n' || c == '\r'); return c; } typedef long long type; const int W = 51; type basis[W + 1]; int siz; void ins(type x) { for (int i = W; i >= 1; i--) { if (x >> (i - 1)) { if (basis[i] == 0) { basis[i] = x; siz++; return; } x ^= basis[i]; } } } int w, n; int main() { cin >> w >> n; for (int i = 1; i <= n; i++) { type x = 0; for (int j = 1; j <= w; j++) { char c; c = read(); if (c == 'O') x += 1ll << (j - 1); } ins(x); } cout << (1ll << siz) % 2008 << endl; }