bzoj5219 [Lydsy2017省队十连测] 最长路径

题意:


做法来自

首先竞赛图缩点后是一条链,\(1\)号节点在开头的那个\(SCC\)中,因此从\(1\)号节点出发的最长链即为\(1\)号节点所在的\(SCC\)的大小\(+1\)号节点拓扑序之后的所有\(SCC\)的大小之和。

\(f_i\)表示\(i\)个点的竞赛图数量,显然有\(f_i=2^{\frac{n*(n-1)}{2}}\)

\(g_i\)表示大小为\(i\)的竞赛图且是\(SCC\)方案数,有:

\(g_i=f_i-\sum\limits_{j=1}^{i-1}C_i^j*g_j*f_{i-j}\)

即枚举拓扑序最小的\(SCC\)大小,容斥一下。

之后枚举\(1\)号节点所在\(SCC\)大小和\(1\)号节点拓扑序之后所有节点个数

\(ans_{i+j}=\sum\limits_{i=1}^n\sum\limits_{j=0}^{n-i}C_{n-1}^{i-1}*C_{n-i}^{j}*g_i*f_j*f_{n-i-j}\)

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2010;
int n;
ll mod;
ll f[maxn],g[maxn],ans[maxn];
ll C[maxn][maxn];
inline void pre_work(int n)
{
	C[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
}
inline ll power(ll x,ll k,ll mod)
{
	ll res=1;
	while(k)
	{
		if(k&1)res=res*x%mod;
		x=x*x%mod;k>>=1;
	}
	return res;
}
int main()
{
	scanf("%d%lld",&n,&mod);
	pre_work(n);
	for(int i=0;i<=n;i++)f[i]=power(2,i*(i-1)/2,mod);
	for(int i=1;i<=n;i++)
	{
		g[i]=f[i];
		for(int j=1;j<i;j++)g[i]=((g[i]-C[i][j]*g[j]%mod*f[i-j]%mod)%mod+mod)%mod;
	}
	for(int i=1;i<=n;i++)
		for(int j=0;j<=n-i;j++)
			ans[i+j]=(ans[i+j]+C[n-1][i-1]*C[n-i][j]%mod*g[i]%mod*f[j]%mod*f[n-i-j]%mod)%mod;
	for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2019-12-19 18:51  nofind  阅读(146)  评论(0编辑  收藏  举报