当前位置: 代码迷 >> 综合 >> [Atcoder Yahoo Contest 2019]E.Odd Subrectangles(思维+线性基)
  详细解决方案

[Atcoder Yahoo Contest 2019]E.Odd Subrectangles(思维+线性基)

热度:142   发布时间:2023-10-22 22:10:53.0

Score : 800800800 points

题面

传送门
翻译有时间再补…

题解

很巧妙的一道题。
在此特别感谢一下SovietPower的博客文章。

首先这是一个01矩阵,因此可以将和的奇偶性看成是异或和是否为1。
按照题解的套路,假如我们已经选好了一些列。
这样的话我们可以确定每行的异或和是000还是111
设有aaa行异或和为111bbb行异或和为000,显然有a+b=ma+b=ma+b=m
题目要求总异或和为111,可以在aaa行中选奇数行,bbb列中随便选。
aaa行中选奇数行的方案数是:Ca1+Ca3+...=2a?1C^{1}_{a}+C^{3}_{a}+...=2^{a-1}Ca1?+Ca3?+...=2a?1(可以查一下杨辉三角的性质)
因此确定一些列的方案数是2a?1?2b=2m?12^{a-1}*2^b=2^{m-1}2a?1?2b=2m?1.
但是如果a=0a=0a=0时,是不满足条件的。
考虑统计这些不合法的情况。
可以转换为将每一行都看成一个二进制数列,统计一下其中子集异或和为0的个数。
这是可以用线性基解决的经典问题。
根据线性基的结论,在线性基里选取任意子集的异或和都不为0。
设线性基的大小为rrr,那么异或等于零的个数就是2n?r2^{n-r}2n?r
那么总答案就是(2n?2n?r)?2m?1(2^n-2^{n-r})*2^{m-1}(2n?2n?r)?2m?1
二进制数列可以用bitset优化一下。
因此时间复杂度为O(n3w)O(\frac{n^3}{w})O(wn3?)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<bitset>
using namespace std;
#define MAXN 300
#define MOD 998244353
int n,m;
bitset<MAXN+5> A[MAXN+5],B[MAXN+5];
int read()
{
    int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){
    if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){
    x=x*10+c-'0';c=getchar();}return x*f; 
}
int fst_pow(int a,int b)
{
    int res=1;while(b){
    if(b&1)res=(1LL*res*a)%MOD;a=(1LL*a*a)%MOD;b>>=1;}return res;
}
int main()
{
    scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)A[i][j]=(read()==1);int r=0;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(A[i][j]){
    if(B[j][j])A[i]^=B[j];else{
    B[j]=A[i];r++;break;}}printf("%d",(fst_pow(2,n+m-1)-fst_pow(2,n-r+m-1)+MOD)%MOD);
}
  相关解决方案