【生成函数+计数】LOJ6389 [THUPC2018] 好图计数

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85260225

【题目】
原题地址
定义 G G 的补图与 G G 有完全相同的节点,任意两点之间有边当且仅当他们在 G G 中不相邻
定义一个无向简单图是好的满足:一个单点是好的,若干个好的图分别作为连通块所形成的图是好的,一个好的图的补图是好的。
给定一个整数 n n ,求 n n 个节点的本质不同的好图数量, n 23333 n\leq 23333

【解题思路】
以下多数参考这里,有部分补充修改。

这个题和无标号生成树计数类似
n n 个点的好图数目为 f n f_n ,其中连通图的数目为 g n g_n ,那么显然当 n 2 n\geq 2 ,连通好图与不连通好图是一一对应的,也就是 f n = 2 g n f_n=2g_n
考虑 f f 的生成函数 F ( x ) = f i x i F(x)=\sum f_ix^i ,为了方便,设 f 0 = 1 f_0=1
首先一个好图由若干个连通好图组成,于是我们考虑枚举每个连通好图的贡献,那么一种大小为 k k 的连通好图的贡献是 i 0 x k i \sum_{i\geq 0} x^{ki} ,因此我们有:
F ( x ) = k > 0 ( i 0 x i k ) g k = k > 0 ( 1 x k ) g k F(x)=\prod_{k>0}(\sum_{i\geq 0}x^{ik})^{g_k}=\prod_{k>0}(1-x^k)^{-g_k}
然后对两边同时取 l n ln
ln ( F ( x ) ) = k > 0 g k ln ( 1 x k ) \ln(F(x))=-\sum_{k>0} g_k\ln(1-x^k)
再求导:
F ( x ) F ( x ) = k > 0 g k k x k 1 1 x k \frac {F'(x)} {F(x)}=\sum_{k>0}g_k\frac {kx^{k-1}} {1-x^k}
然后拆回去每一项:
[ x n ] F ( x ) = ( n + 1 ) f n + 1 = i = 0 n f i ( [ x n i ] k > 0 k g k x k 1 1 x k ) [x^n]F(x)=(n+1)f_{n+1}=\sum\limits_{i=0}^nf_i([x^{n-i}]\sum\limits_{k>0}kg_k\frac{x^{k-1}}{1-x^k})
这里注意到 x k 1 1 x k = i > 0 x i k 1 \frac{x^{k-1}}{1-x^k}=\sum_{i>0}x^{ik-1} ,则 [ x n ] x k 1 1 x k = [ k n + 1 ] [x^n]\frac{x^{k-1}}{1-x^k}=[k|n+1] ,因此
( n + 1 ) f n + 1 = i = 0 n f i k n + 1 i k g k (n+1)f_{n+1}=\sum_{i=0}^nf_i\sum_{k|n+1-i}kg_k
注意 i = 0 i=0 时要移项,且 f 0 = 1 , g i = f i 2 f_0=1,g_i=\frac {f_i} 2 ,所以得:
n + 1 2 f n + 1 = k n + 1 , k < n + 1 k g k + i = 1 n f i k n + 1 i k g k \frac{n+1}{2}f_{n+1}=\sum\limits_{k|n+1,k<n+1}kg_k+\sum\limits_{i=1}^nf_i\sum\limits_{k|n+1-i}kg_k
s i = k i k g k s_i=\sum_{k|i}kg_k 可以 O ( n 2 ) O(n^2) 递推,然后卡常是可以过的。
观察到上面还是一个卷积的形式,于是用分治 FFT \text{FFT} 可以做到 O ( n log 2 n ) O(n\log^2 n)

所以我们就直接上暴力了。

【参考暴力】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=23333;
ll T,mod;
ll f[N+5],g[N+5],s[N+5];

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}
ll qpow(ll x,ll y){ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
ll upm(ll x){return x>=mod?x-mod:x;}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("LOJ6389.in","r",stdin);
	freopen("LOJ6389.out","w",stdout);
#endif
	T=read();mod=read();
	f[0]=f[1]=1;
	for(int i=1;i<=N;++i)s[i]=1;
	for(int i=1;i<N;++i)
	{
		__int128 tmp=0;
		for(int j=0;j<=i;++j) tmp+=f[j]*s[i+1-j];
		tmp%=mod;g[i+1]=tmp*qpow(i+1,mod-2)%mod;f[i+1]=g[i+1]*2%mod;
		for(int j=i+1;j<=N;j+=i+1)s[j]=upm(s[j]+tmp);
	}
	cerr<<clock()<<endl;
	while(T--) printf("%lld\n",f[read()]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85260225
今日推荐