【YBTOJ】【Luogu P3857】[TJOI2008]彩灯
链接:
题目大意:
可以对一个长度 \(n\) 的 01 串的 \(m\) 组特定位置异或 \(1\),你可以选其中任意几个操作,求能异或出多少个数。
正文:
我们可以换种想法:每次操作相当于把一个 01 串和原串进行异或,求出能异或多少个数。
然后我们知道,在一个数 \(x\) 插入线性基时,可能会因为线性基里的元素早就已经可以异或出 \(x\) 而失败。而这不就是判重吗,那么重复第数字已经被去掉了,剩下的数字可以异或出最多的数,假设剩下 \(k\) 个数,那么 \(2^k\) 就是答案了。
代码:
int n, m;
char s[N];
ll a[N];
void add (ll val)
{
for (int i = 50; i + 1; --i)
{
if (!(val & (1ll << i))) continue;
if (a[i])
val ^= a[i];
else
{
a[i] = val;
return ;
}
}
}
int main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
scanf ("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
ll val = 0;
scanf ("%s", s + 1);
for (int i = 1; i <= n; i++)
if (s[i] == 'O') val |= 1ll << (i - 1);
add (val);
}
ll ans = 0;
for (int i = 0; i <= 50; i ++)
if (a[i]) ans ++;
printf ("%lld\n", (1ll << ans) % mod);
return 0;
}