LOJ6389 好图计数

好图计数

这道题目非常简单,它甚至没有题目背景、没有任何故事。

但为了能让你顺利理解题目,善良的 Yazid 将为你介绍一些概念。

  • 简单图:不存在重边、自环的图。(重边即为两条完全相同的边,自环即为两端点为同一节点的边)

  • 补图:一个图 \(G\) 的补图有与 \(G\) 完全相同的节点,且任意两点之间有边当且仅当他们在 \(G\) 中不相邻。

我们归纳定义一个无向简单图是好的

  1. 一个单点是好的。

  2. 若干个好的图分别作为联通块所形成的图是好的。

  3. 一个好的图的补图是好的。

给定一个正整数 \(n\)

\(n\) 个点的本质不同的好的图的数量对质数 \(P\) 取模的结果。(这里的 \(P\) 是一个常数,具体见【输入格式】)

两个好的图的被认为是本质不同的,当且仅当无论如何将一个图重标号,它都不能与另一个图完全相同。

保证 \(T\leq 233\)\(n\leq 23333\)\(2^{29} < P < 2^{30}\) 且保证 \(P\) 为质数。

题解

https://jklover.hs-blog.cf/2020/07/19/Loj-6389-好图计数/#more

生成函数+欧拉变换。

好图肯定是由若干个完全图组合起来的。

对于一张连通的图,若它的补图也是连通图,根据定义,当 \(n>1\) 时,它们都不是好图.而不连通的图的补图一定是连通的,于是可以得出,当 \(n>1​\) 时,连通好图和不连通好图是可以用补图关系一一对应的,两者数目相等.

\(f_i\) 表示 \(i\) 个点的好图的数目, \(g_i\) 表示 \(i\) 个点连通好图的数目,则有 \(f_0=f_1=g_1=1,f_i=2\cdot g_i(i>1)\) .

考虑 \(f_i\) 的生成函数 \(F(x)\) ,枚举大小为 \(k​\) 的连通块数目,在无标号下可以得出

\[F=\prod_{k\ge 1}(1-x^k)^{-g_k} \]

\[\ln(F)=\sum_{k\ge 1}-g_k\cdot \ln(1-x^k) \]

\[\frac{F’}{F}=\sum_{k\ge 1} g_k\cdot \frac{kx^{k-1}}{1-x^k} \]

\[[x^n]F’=[x^n] (F\cdot \sum_{k\ge 1} g_k\cdot \frac{kx^{k-1}}{1-x^k}) \]

\[(n+1)f_{n+1}=\sum_{i=0}^n f_i\cdot [x^{n-i}]\sum_{k\ge1} g_k\cdot \frac{kx^{k-1}}{1-x^k} \]

\[(n+1)f_{n+1}=\sum_{i=0}^n f_i\cdot\sum_{k\ge 1,k|n-i+1}g_k\cdot k \]

\[\frac{n+1} 2f_{n+1}=\sum_{i=0}^n f_i\cdot\sum_{1\le k<n+1,k|n-i+1}g_k\cdot k \]

依次枚举 \(n\) ,过程中暴力维护每个 \(\sum g_k\cdot k\) ,时间复杂度 \(O(n^2)\) .

需要老生常谈的取模优化才能通过这题。

CO int N=23333+1;
CO int64 inf=4e18;
int inv[N];
int f[N],g[N],h[N];

void update(int k){
	int val=mul(k,g[k]);
	for(int i=k;i<N;i+=k) inc(h[i],val);
}
int main(){
	int T=read<int>();read(mod);
	f[0]=f[1]=g[1]=inv[1]=1;
	update(1);
	for(int n=1;n<N-1;++n){
		int64 sum=0;
		for(int i=0;i<=n;++i){
			sum+=(int64)f[i]*h[n-i+1];
			if(sum>inf) sum%=mod;
		}
		inv[n+1]=mul(mod-mod/(n+1),inv[mod%(n+1)]);
		g[n+1]=mul(sum%mod,inv[n+1]);
		f[n+1]=add(g[n+1],g[n+1]);
		update(n+1);
	}
	while(T--) printf("%d\n",f[read<int>()]);
	return 0;
}

posted on 2020-07-21 07:22  autoint  阅读(93)  评论(0编辑  收藏

导航