AT2062

前言

CMLL02_AK_DSPOLY.jpg

思路

考虑把“不能”的关系对应上图的一条有向边,我们怎么做。

不妨记 \(f_k\) 表示从图中选出 \(k\) 条边的可行方案数。

那么我们由子集反演,立刻得到:

\[Ans=\sum_k(-1)^k(n-k)!f_k \]

于是我们要做的是快速统计 \(f\)

仔细观察这张图中哪些边会冲突

显然就是起点或终点相同的边

由于这张图是由许多链组成的,考察每一条链状结构;具体地,形如:

\[a\rightarrow b\leftarrow c\rightarrow d\rightarrow\cdots \leftarrow z \]

这样的链不能取相邻项,且除此之外的链均与此链无冲突关系。

记链上有 \(p\) 个顶点,那就是统计对于每种边数,链上有几种取法。

显然这就是所谓无标号 \(\operatorname{SEQ}\) 构造的形式,不难得其为:

\[\\ [u^p]{1\over1-u-zu^2} \\={({1+\sqrt{1+4z}\over2})^{p+1}-({1-\sqrt{1+4z}\over2})^{p+1}\over\sqrt{1+4z}} \\\]

对每条这样的链都做一遍,然后暴力乘起来就好了。

顺带提一句,其实 \(924844033\) 也是 NTT 模数。

Code

\(n\) 较小,采取了暴力多项式。

以下放核心代码。

using namespace BF_POLY;
poly Pow(poly base,uint index,uint prec)
{
    base.chg_siz(prec);
    poly ans(modvec{1});
    while(index)
    {
        if(index&1)ans*=base,ans.chg_siz(prec);
        base*=base,base.chg_siz(prec);index>>=1;
    }
    return ans;
}
int main()
{
    AnyMod::ChgMod(924844033);
    uint n,k;scanf("%u%u",&n,&k);
    poly User({1,4});
    User=User.sqrt(n+2);
    poly Inv=User.inv(n+2);
    poly QAQ(modvec{1});
    for(uint i=0;i<k;i++)
    {
        uint p=(n-i-1)/k+1;
        poly P=
            (Pow((modint(1)+User)*modint(2).inv(),p+1,p+1)-
            Pow((modint(1)-User)*modint(2).inv(),p+1,p+1))
            *cpd().chg_siz(Inv,p+1);
        P.chg_siz(p+1);
        QAQ*=P*P;
    }
    modint ans=0,v(1);
    for(uint i=n;~i;i--)
    {
        ans+=(i&1?AnyMod::Mod-1:1)*v*QAQ.val(i);
        v*=n-i+1;
    }
    ans.println();
    return 0;
}
posted @ 2022-07-13 13:08  myee  阅读(18)  评论(0编辑  收藏  举报