【GDOI2018模拟7.8】矩阵

【GDOI2018模拟7.8】矩阵

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

先看题意, 题目让我们求使得一个已有 k <script type="math/tex" id="MathJax-Element-9068">k</script>个点被钦定的 nm01 <script type="math/tex" id="MathJax-Element-9069">nm\;01</script>矩阵各行各列异或和皆为1的方案数。

有一个数据 n <script type="math/tex" id="MathJax-Element-9070">n</script>、 m <script type="math/tex" id="MathJax-Element-9071">m</script>奇偶性不同,用PY想想就知道答案显然为零。

1. <script type="math/tex" id="MathJax-Element-9072">1.</script>最 naive <script type="math/tex" id="MathJax-Element-9073">naive</script>的想法,状压一维,扫另一维,问题就可以在 nm2min(n,m) <script type="math/tex" id="MathJax-Element-9074">nm2^{min(n,m)}</script>的时间内求解。

台下的吃瓜群众们:“然而无论是 n <script type="math/tex" id="MathJax-Element-9075">n</script>还是 m <script type="math/tex" id="MathJax-Element-9076">m</script>都达到了 105 <script type="math/tex" id="MathJax-Element-9077">10^5</script>的数量级,怎么破?”

2. <script type="math/tex" id="MathJax-Element-9078">2.</script>是时候考察 k <script type="math/tex" id="MathJax-Element-9079">k</script>了。我们发现 k <script type="math/tex" id="MathJax-Element-9080">k</script>始终 10m(n) <script type="math/tex" id="MathJax-Element-9081">\leqslant10m(n)</script>,由抽屉原理可得存在一列,其的被钦定点数 10 <script type="math/tex" id="MathJax-Element-9082">\leqslant10</script>,不妨取被钦定点数最小的一列 x <script type="math/tex" id="MathJax-Element-9083">x</script>,被钦定点数为 p <script type="math/tex" id="MathJax-Element-9084">p</script>,那么除这p行以外的行最终都可以由第 x <script type="math/tex" id="MathJax-Element-9085">x</script>列下的自由格纠正异或值。到此为止,我们已经把行数的数量级降到了 10 <script type="math/tex" id="MathJax-Element-9086">10</script>以内。

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

3. <script type="math/tex" id="MathJax-Element-9087">3.</script>我们找出所有列构成 B <script type="math/tex" id="MathJax-Element-9088">B</script>使得每一列都存在那 p <script type="math/tex" id="MathJax-Element-9089">p</script>列以外的自由格,那么无论其他格如何操作,都预留一个自由格来进行最后的纠正,那么 B <script type="math/tex" id="MathJax-Element-9090">B</script>中每一列对答案乘数的贡献是 2p1 <script type="math/tex" id="MathJax-Element-9091">2^{那p列之外自由格数-1}</script>。那么那p列之中呢?我们发现我们可以一并计算这 |B|+1 <script type="math/tex" id="MathJax-Element-9092">|B|+1</script>列在那 p <script type="math/tex" id="MathJax-Element-9093">p</script>行中分别异或成 0 <script type="math/tex" id="MathJax-Element-9094">0</script>或 1 <script type="math/tex" id="MathJax-Element-9095">1</script>的方案数,然后DP那 p <script type="math/tex" id="MathJax-Element-9096">p</script>行和剩下的列就可以了。由于剩下的列里都至少有 npn <script type="math/tex" id="MathJax-Element-9097">n-p\approx n</script>格被钦定,所以这些列的总数不超过 kn <script type="math/tex" id="MathJax-Element-9098">\frac{k}{n}</script>,总复杂度为 O((n+m+k)+k2nm2km) <script type="math/tex" id="MathJax-Element-9099">O(预处理(大概是n+m+k)+\frac{k^2}{nm}*2^\frac{k}{m})</script>。

#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;
}
//记得取模 
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页