[洛谷P3857] [TJOI2008]彩燈

P3857 [TJOI2008]彩燈

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;
}
相關文章
相關標籤/搜索