C - Fluorescent 2
首先将三次方转化一下,设进行操作后,第 个位置的开关情况为
(
表示关,
表示开),那么三次方就变成了:
再转化一下:
对三项分别计算即可。
先计算第一项,枚举每一项 ,发现这时只和字符串第
列有关,如果该列全为
,则方案数为
。
接下来考虑存在至少一个 的情况,可以先选一个
,设其在第
行,那么另外
个位置任意选或不选,选择完毕后如果开关开了,那么就可以不选第
行,反之就选,所以方案数为
。
接下来计算第二项,这里可以枚举 和
,接下来为了方便,设第
列形成的二进制数为
,并且由于后面的方案数计算和计算第一项时类似,就不展开了,只给结论。
,方案数为
.
,方案数为
.
,方案数为
.
,方案数为
.
然后是第三项,继续分类讨论,实现(计算每种情况的个数)见代码:
,
.
,
.
,
.
,
.
,
.
互不相等,都不为
,
,
.
,
.
互不相等,都不为
,
,
.
int n, m; char s[N][M]; ll bit[M]; bool F[M];
map<ll, int> mp; mint pw[N], C[M][M];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int lim = 51;
pw[0] = 1;
forn (i, 1, lim) pw[i] = pw[i - 1] * mint(2);
lim = 1000;
C[0][0] = 1;
forn (i, 1, lim) {
C[i][0] = 1;
forn (j, 1, lim) C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
while (cin >> n >> m) {
mp.clear();
rep (i, 0, n) cin >> s[i];
rep (j, 0, m) {
bit[j] = 0;
rep (i, 0, n) bit[j] = bit[j] << 1 | ((int)s[i][j] - int('0'));
if (mp.count(bit[j])) F[j] = 0;
else F[j] = 1;
mp[bit[j]] ++ ;
}
mint ans = 0;
// case 1 单个数字
rep (i, 0, m)
if (bit[i]) ans += pw[n - 1];
else ans += pw[n];
// case 2 两个数字
rep (i, 0, m) rep (j, i + 1, m)
if (!bit[i] && !bit[j])
ans += mint(6) * pw[n];
else if (!bit[i] || !bit[j] || (bit[i] == bit[j]))
ans += mint(6) * pw[n - 1];
else
ans += mint(n >= 2) * mint(6) * pw[n - 2];
// case 3 三个数字
mint cnt = C[m][3]; int n0 = 0;
// case 3.1 bit[i] = bit[j] = bit[k] = 0
if (mp.count(0ll)) {
n0 = mp[0];
cnt -= C[n0][3];
ans += mint(6) * C[n0][3] * pw[n];
}
// case 3.2 bit[i] != 0, bit[j] = bit[k] = 0
rep (i, 0, m) if (bit[i] && F[i]) //#
ans += mint(6) * C[n0][2] * mint(mp[bit[i]]) * pw[n - 1],
cnt -= C[n0][2] * mint(mp[bit[i]]);
// case 3.3 bit[i] != 0, bit[j] != 0, bit[k] = 0 \and bit[i] = bit[j]
rep (i, 0, m) if (bit[i] && F[i]) //#
ans += mint(6) * C[mp[bit[i]]][2] * mint(n0) * pw[n - 1],
cnt -= C[mp[bit[i]]][2] * mint(n0);
// case 3.4 bit[i] != 0, bit[j] != 0, bit[k] = 0 \and bit[i] != bit[j]
rep (i, 0, m) rep (j, i + 1, m) //#
if (bit[i] && bit[j] && bit[i] != bit[j])
ans += mint(n >= 2) * mint(6) * mint(n0) * pw[n - 2],
cnt -= mint(n0);
// case 3.5 bit[i] = bit[j] = bit[k] != 0;
rep (i, 0, m) if (bit[i] && F[i]) //#
ans += mint(6) * C[mp[bit[i]]][3] * pw[n - 1],
cnt -= C[mp[bit[i]]][3];
// case 3.6 bit[i], bit[j], bit[k] 互不相等,都不为零 bit[i] ^ bit[j] == bit[k]
int cur = 0;
rep (i, 0, m) rep (j, i + 1, m) // #
if (bit[i] && bit[j] && mp.count(bit[i] ^ bit[j]) && (bit[i] ^ bit[j]))
ans += mint(2) * mint(n >= 2) * mp[bit[i] ^ bit[j]] * pw[n - 2],
cur += mp[bit[i] ^ bit[j]];
cur /= 3, cnt -= mint(cur);
// case 3.7 bit[i] = bit[j] != 0, bit[k] != 0
rep (i, 0, m) if (bit[i] && F[i])
ans += mint(6) * mint(n >= 2) * C[mp[bit[i]]][2] * mint(m - n0 - mp[bit[i]]) * pw[n - 2],
cnt -= C[mp[bit[i]]][2] * mint(m - n0 - mp[bit[i]]);
// case 3.8 bit[i], bit[j], bit[k] 互不相等,都不为零 bit[i] ^ bit[j] != bit[k]
if (n >= 3) ans += mint(6) * cnt * pw[n - 3];
cout << ans.r << '\n';
}
return 0;
}