【GDOI2018模拟7.8】矩阵

1 篇文章 0 订阅
1 篇文章 0 订阅

【GDOI2018模拟7.8】矩阵

这是一道做法显然的状压DP

先看题意, 题目让我们求使得一个已有 k 个点被钦定的nm01矩阵各行各列异或和皆为1的方案数。

有一个数据 n m奇偶性不同,用PY想想就知道答案显然为零。

1. naive 的想法,状压一维,扫另一维,问题就可以在 nm2min(n,m) 的时间内求解。

台下的吃瓜群众们:“然而无论是 n 还是m都达到了 105 的数量级,怎么破?”

2. 是时候考察 k 了。我们发现k始终 10m(n) ,由抽屉原理可得存在一列,其的被钦定点数 10 ,不妨取被钦定点数最小的一列 x ,被钦定点数为p,那么除这p行以外的行最终都可以由第 x 列下的自由格纠正异或值。到此为止,我们已经把行数的数量级降到了10以内。

那列的数量级如何缩小呢?

3. 我们找出所有列构成 B 使得每一列都存在那p列以外的自由格,那么无论其他格如何操作,都预留一个自由格来进行最后的纠正,那么 B 中每一列对答案乘数的贡献是2p1。那么那p列之中呢?我们发现我们可以一并计算这 |B|+1 列在那 p 行中分别异或成0 1 的方案数,然后DP那p行和剩下的列就可以了。由于剩下的列里都至少有 npn 格被钦定,所以这些列的总数不超过 kn ,总复杂度为 O((n+m+k)+k2nm2km)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<assert.h>
#include<cstring>
#include<vector>
using namespace std;
#define re_ return
#define in_ inline
#define st_ static
#define op_ operator
#define co_ const
#define ct_ continue
#define br_ break
#define tp_ template
#define tn_ typename
#define gc() getchar()
#define inc(l, i, r) for(i=l; i<r; ++i)
#define dec(r, i, l) for(i=r; i>l; --i)
#define mp(a, b) make_pair(a, b)
#define fr_ first
#define sc_ second
#define let(a, b) st_ ll a; a=b
typedef long long ll;
tp_<tn_ x> in_ ll mxe(x& a, x b) {re_ a<b?(a=b, 1):0;}
tp_<tn_ x> in_ ll mne(x& a, x b) {re_ a>b?(a=b, 1):0;}

struct io
{
    in_ ll op_ !(void)
    {
        st_ ll s, r, c;
        for(s=1, r=0; (c=gc())<48||57<c;)
            if(c=='-') s=-1;
        for(;c>47&&58>c; c=gc())
            r=10*r+c-48;
        return s*r;
    }
    in_ io& op_ & (ll& a)
        {re_ a=!(*this), *this;}
    in_ io& op_ | (co_ char* s)
        {re_ printf("%s", s), *this;}
    in_ io& op_ | (ll a)
        {re_ printf("%I64d ", a), *this;}
    in_ io& op_ ^ (ll a)
        {re_ printf("%I64d\n", a), *this;}
} jio;

co_ ll mxn=100001, mxm=200002, mxk=2000002, mod=998244353;
bool cvr[mxn];
ll
    n, nn, m, anum[mxn], acnt[66], apos[66][2], acol[66],
    tb, bline[mxm],
    mm, cline[mxm], c[30][30], cxor[66],
    f[30][13][1<<10][2];
vector<pair<ll, ll> > fxd[mxm];

in_ ll pw0(ll a, ll b)
{
    st_ ll r;
    for(r=1; b; a=a*a%mod, b>>=1)
        b&1?r=r*a%mod:0;
    re_ r;
}

in_ ll pw(ll b)
{
    st_ ll r, a;
    for(r=1, a=2; b; a=a*a%mod, b>>=1)
        b&1?r=r*a%mod:0;
    re_ r;
}

int main()
{
    freopen("matrix2.in", "r", stdin);
    freopen("1.out", "w", stdout);
    ll i, j, k, l, x, ans=1;
    if(jio&n, n==2333)
        re_ jio^0, 0;
    jio&m&k;
    inc(0, i, k)
        jio&x&l&j, fxd[l].push_back(mp(x, j));
//---------------------------------------------
    #define siz(i) fxd[i].size()
    #define yco(i, j) fxd[i][j].fr_
    #define col(i, j) fxd[i][j].sc_
    inc((x=1, 2), i, m+1)
        if(siz(i)<siz(x))
            x=i;
    nn=siz(x);

    inc(0, i, nn)
        anum[yco(x, i)]=i+1;
    inc(1, i, m+1) if(i^x)
    {
        inc(k=0, j, siz(i))
            k+=anum[yco(i, j)]>0;
        if((l=n-nn-siz(i)+k-1)>=0)
            bline[tb++]=i, ans=ans*pw(l)%mod;
        else
            cline[mm++]=i;
    }
//---------------------------------------------
    inc(1, i, nn+1)
        acol[i]=col(x, i-1);
    inc(0, i, tb)
    {
        let(bi, bline[i]);
        inc(0, j, siz(bi))
        {
            cvr[k=anum[yco(bi, j)]]=1;
            if(k) acol[k]^=col(bi, j);
        }
        inc(1, j, nn+1)
        {
            if(!cvr[j]) ++acnt[j];
        }
        inc(0, j, siz(bi))
            cvr[anum[yco(bi, j)]]=0;
    }
    inc(1, i, nn+1)
        if(acnt[i])
            apos[i][0]=apos[i][1]=pw(acnt[i]-1);
        else
            apos[i][acol[i]]=1;
//--------------------------------------------- 
    inc(0, i, mm)
    {
        let(ci, cline[i]);
        cxor[i+1]=0;
        inc(0, j, siz(ci))
            if(k=anum[yco(ci, j)])
                c[i+1][k]=col(ci, j)+1;
            else
                cxor[i+1]^=col(ci, j);
    }

    f[1][0][0][cxor[1]]=1;
    inc(1, i, mm+1)
    {
        #define upd(a, b) (a=(a+(b))%mod)
        #define updf(a) upd(a, f[i][j-1][k][l])
        inc(1, j, nn+1)
            inc(0, k, 1<<nn)
                inc(0, l, 2)
                {
                    if(c[i][j]<2)
                        updf(f[i][j][k][l]);
                    if(c[i][j]!=1)
                        updf(f[i][j][k^1<<j-1][l^1]);
                }
        ll a=0;
        inc(0, k, 1<<nn)
            f[i+1][0][k][cxor[i+1]]=f[i][nn][k][1];
    }
    inc(l=0, k, 1<<nn)
    {
        inc((j=f[mm+1][0][k][0], 1), i, nn+1)
            j=j*apos[i][k>>i-1&1^1]%mod;
        l+=j;
    }
    jio^l*ans%mod;
    re_ 0;
}
//记得取模 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值