Description
给定n和p
对于i从1到n,求n个点形成的,从1出发最长路恰好为i的竞赛图数量,对p取模
n≤2000n\le2000n≤2000
Solution
由一些小常识可以知道,竞赛图一定存在一条哈密顿路径,且强连通分量缩点之后形成的,一定是一条若干scc形成的链,拓扑序小的scc向后连满边
也就是说,1为起点的最长路,一定是从1出发,向后走完所有scc。所以最长路=n-[1走不到的点]
考虑设f[n]表示n个节点的答案,g[n]表示n个点形成竞赛图强连通的方案。推g可以容斥
g[n]=2(n2)−∑i=1n−12(i2)g[n−i](ni)g[n]={2^{\binom{n}{2}}}-\sum_{i=1}^{n-1}{2^{\binom{i}{2}}g[n-i]\binom{n}{i}}g[n]=2(2n)−i=1∑n−12(2i)g[n−i](in)
考虑怎么求f,我们枚举1所在scc的大小i,然后枚举1能到达其余scc的大小之和j,那么答案就是
f[i+j]=(n−1i−1)g[i]2(j2)2(n−i−j2)f[i+j]=\binom{n-1}{i-1}g[i]2^{\binom{j}{2}}2^{\binom{n-i-j}{2}}f[i+j]=(i−1n−1)g[i]2(2j)2(2n−i−j)
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;
}