【BZOJ】5219: [Lydsy2017省队十连测]最长路径 组合计数&竞赛图性质

传送门:bzoj5219


题解

竞赛图性质:

  • 必然存在一条哈密尔顿路径
  • 缩点之后按拓扑序形成一条“链”

由竞赛图性质得到从点1出发的最长路径上点数等于1所在 s c c scc scc点数+拓扑序在1(链中靠后)的 s c c scc scc的点的总数。

f [ n ] f[n] f[n]表示有 n n n个节点的竞赛图的个数,显然: f [ n ] = 2 n ( n − 1 ) 2 f[n]=2^{\frac{n(n-1)}{2}} f[n]=22n(n1)

g [ n ] g[n] g[n]表示有 n n n个节点的竞赛图强连通分量,考虑枚举拓扑序最小的 s c c scc scc进行容斥:
g [ n ] = f [ n ] − ∑ i = 1 n − 1 ( n i ) g [ i ] f [ n − i ] g[n]=f[n]-\sum\limits_{i=1}^{n-1}\binom {n}{i}g[i]f[n-i] g[n]=f[n]i=1n1(in)g[i]f[ni]

初始 f [ 0 ] = 1 , g [ 1 ] = 1 f[0]=1,g[1]=1 f[0]=1,g[1]=1,其余递推得到。

a n s [ n ] ans[n] ans[n]表示则点1出发最长路径为 n n n的方案数。枚举1所在 s c c scc scc点数以及链中靠后的总点数:

a n s [ n ] = ∑ i = 1 n ( n − 1 i − 1 ) ( n − i j ) g [ i ] f [ j ] f [ n − i − j ] ans[n]=\sum_{i=1}^n\binom{n-1}{i-1}\binom{n-i}{j}g[i]f[j]f[n-i-j] ans[n]=i=1n(i1n1)(jni)g[i]f[j]f[nij]

组合数线性递推预处理即可。


代码

#include
#define RI register
using namespace std;
typedef long long ll;
const int N=2020;

int n,mod,c[N][N];
int f[N],g[N],ans[N];

inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}

inline int fp(int x,int y)
{
	int re=1;
	for(;y;y>>=1,x=mul(x,x))
	 if(y&1) re=mul(re,x);
	return re;
}

int main(){
    RI int i,j,res;
    scanf("%d%d",&n,&mod);
	f[0]=g[1]=1;
	for(i=0;i<=n;++i){
		c[i][0]=c[i][i]=1;
		for(j=1;j<i;++j)
		 c[i][j]=ad(c[i-1][j],c[i-1][j-1]);
	}
    for(i=1;i<=n;++i) f[i]=fp(2,i*(i-1)/2);
	for(i=2;i<=n;++i){
		res=0;
		for(j=1;j<i;++j)
			res=ad(res,mul(c[i][j],mul(g[j],f[i-j])));
        g[i]=dc(f[i],res);
	}
	for(i=1;i<=n;++i){
		for(j=n-i;~j;--j) 
		 ans[i+j]=ad(ans[i+j],(ll)c[n-1][i-1]*c[n-i][j]%mod*(ll)f[j]%mod*(ll)g[i]%mod*(ll)f[n-i-j]%mod);
	}
	for(i=1;i<=n;++i) printf("%d\n",ans[i]);
	return 0;
}

你可能感兴趣的:(---组合数学---,竞赛图)