OwO 题目含义都是一样的,只是数据范围扩大了
对于n<=7的问题,我们直接暴力搜索就可以了
对于n<=1000的问题,我们不难联想到<主旋律>这一道题
没错,只需要把方程改一改就可以了
首先我们考虑不合法的方案强连通分量缩点后一定是DAG
考虑子问题:DAG计数
做法可以参考<cojs DAG计数1-4 题解报告>
这里给出转移方程
f(n)=sigma((-1)^(k-1)*C(n,k)*2^(k*(n-k))*f(n-k))
如果考虑上强连通分量缩点的情况呢?
我们可以定义g(n)表示n个点可以组成若干个不相连的强连通分量的情况
考虑将容斥系数算进去,那么如果组成奇数个强连通分量,对g(n)贡献为1,否则为-1
定义f(n)为n个点的强连通图的个数
不难得到递推式g(n)=f(n)-sigma(C(n-1,k-1)*f(k)*g(n-k))
含义是考虑某个点所在的强连通分量的大小,枚举大小k,那么选择方案为C(n-1,k-1)
如果大小为n,那么贡献为f(n)
否则贡献部分是-g(n-k)*f(k),注意到这里由于多了一个强连通分量
所以奇偶性发生改变,g的正负也发生改变
之后我们定义h(n)表示n个点的有向图的个数,不难得到h(n)=2^(n*(n-1))
考虑利用容斥来求解f(n),类比上面求解DAG,可以得到如下递推式
f(n)=h(n)-sigma(C(n,k)*2^(k*(n-k))*h(n-k)*g(k))+f(n)
这个递推式的含义是枚举一些点组成的强连通分量在缩点后的出度为0
那么这些点内部的方案算上容斥系数之后就是g(n)
选出点的方案是C(n,k),剩下(n-k)个点向这k个点任意连边,方案为2^(k*(n-k))
剩下(n-k)个点之间任意连,方案为h(n-k)
注意到这里的+f(n)是因为当n=k的时候,这一坨式子得到的是g(n),而我们只能容斥掉组成的强连通分量>1的方案
这样我们就得到了一个O(n^2)的递推式,可以做n<=1000了
对于n<=10w的问题,我们考虑利用FFT优化上面的式子
上面的式子中f有g,g有f,是非常恶心的
考虑这个式子f(n)=h(n)-sigma(C(n,k)*2^(k*(n-k))*h(n-k)*g(k))+f(n)
两边f可以抵消,我们提出一个g(n)出来之后可以得到只关于g的递推式
g(n)=h(n)-sigma(C(n,k)*2^(k*(n-k))*h(n-k)*g(k)) (k->(n-1))
关于2^(k*(n-k))如何转化成标准FFT形式在DAG计数的时候已经说过了
即nk=n^2/2+k^2/2-(n-k)^2/2
然后做一发CDQ+FFT我们就可以求出g函数了
之后考虑g(n)=f(n)-sigma(C(n-1,k-1)*f(k)*g(n-k))
由于g函数已知,我们移项得到
g(n)+sigma(C(n-1,k-1)*f(k)*g(n-k))=f(n)
在做一发CDQ+FFT我们就可以求出f函数了
总时间复杂度O(nlog^2n)