bzoj5219 [Lydsy2017省队十连测]最长路径 容斥+dp

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/89313202

Description


给定n和p
对于i从1到n,求n个点形成的,从1出发最长路恰好为i的竞赛图数量,对p取模
n 2000 n\le2000

Solution


由一些小常识可以知道,竞赛图一定存在一条哈密顿路径,且强连通分量缩点之后形成的,一定是一条若干scc形成的链,拓扑序小的scc向后连满边
也就是说,1为起点的最长路,一定是从1出发,向后走完所有scc。所以最长路=n-[1走不到的点]

考虑设f[n]表示n个节点的答案,g[n]表示n个点形成竞赛图强连通的方案。推g可以容斥
g [ n ] = 2 ( n 2 ) i = 1 n 1 2 ( i 2 ) g [ n i ] ( n i ) g[n]={2^{\binom{n}{2}}}-\sum_{i=1}^{n-1}{2^{\binom{i}{2}}g[n-i]\binom{n}{i}}
考虑怎么求f,我们枚举1所在scc的大小i,然后枚举1能到达其余scc的大小之和j,那么答案就是
f [ i + j ] = ( n 1 i 1 ) g [ i ] 2 ( j 2 ) 2 ( n i j 2 ) f[i+j]=\binom{n-1}{i-1}g[i]2^{\binom{j}{2}}2^{\binom{n-i-j}{2}}

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int N=2005;

LL f[N],g[N],ans[N];
LL C[N][N]; int MOD;

LL ksm(LL x,LL dep) {
	LL res=1;
	for (;dep;dep>>=1,x=x*x%MOD) {
		(dep&1)?(res=res*x%MOD):0;
	}
	return res;
}

void upd(LL &x,LL v) {
	x+=v,(x>=MOD)?(x-=MOD):0;
}

int main(void) {
	// freopen("data.in","r",stdin);
	// freopen("myp.out","w",stdout);
	int n; scanf("%d%d",&n,&MOD);
	C[0][0]=1;
	rep(i,1,n) {
		C[i][0]=C[i][i]=1;
		rep(j,1,i-1) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
	}
	f[0]=g[0]=1;
	rep(i,1,n) {
		f[i]=g[i]=ksm(2,i*(i-1)/2);
		rep(j,1,i-1) {
			g[i]=(g[i]+MOD-f[j]*g[i-j]%MOD*C[i][j]%MOD)%MOD;
		}
	}
	rep(i,1,n) rep(j,0,n-i) {
		upd(ans[i+j],g[i]*C[n-1][i-1]%MOD*C[n-i][j]%MOD*f[j]%MOD);
	}
	rep(i,1,n) printf("%lld ", (ans[i]*f[n-i]%MOD+MOD)%MOD); puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/89313202
今日推荐