分析:
很显然,最长路径一定是唯一的。
考虑这么证明:对终点v而言,所有不在路径上的点一定指向它。
然后,对于次终的点u而言,如果它指向任意一个不在路径上的点,那么可以通过u->x->v,得到一条更长的路径,所以所有不在路径上的点也一定指向它
……
综上,除了最长路径以外,所有点都指向这条路径。
那么,就可以DP了
定义DP(i,j)DP(i,j)DP(i,j)表示:i个点的竞赛图,构成最长长度为j的路径的方案数。
显然,对于不在路径上的点,其两两之间任意连边均可,唯一要考虑的就是路径上的点。
因此,若i>j若i>j若i>j,DP(i,j)=DP(j,j)∗2C(i−j,2)DP(i,j)=DP(j,j)*2^{C(i-j,2)}DP(i,j)=DP(j,j)∗2C(i−j,2)
现在就是当i=ji=ji=j时怎么办,很显然,对于一个i个点的图,合法的jjj满足0≤j≤i0\leq j\leq i0≤j≤i,因此,可以用一下容斥:即总方案数(2(C(i,2)))(2^{(C(i,2))})(2(C(i,2))),减去所有j<ij<ij<i的DP值,就可以得到DP(i,i)DP(i,i)DP(i,i)的值。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 2010
using namespace std;
typedef long long ll;
ll C[MAXN][MAXN],dp[MAXN][MAXN];
ll MOD;
void prepare(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-1]+C[i-1][j])%MOD;
}
}
ll fsp(ll x,ll y){
ll res=1;
while(y){
if(y&1ll)
res=res*x%MOD;
x=x*x%MOD;
y>>=1ll;
}
return res;
}
int main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
int n;
SF("%d%d",&n,&MOD);
prepare(n);
for(ll i=1;i<=n;i++){
ll sum=0;
for(ll j=1;j<i;j++){
dp[i][j]=C[i-1][j-1]*dp[j][j]%MOD*fsp(2,(i-j)*(i-j-1)/2ll)%MOD;
(sum+=dp[i][j])%=MOD;
// PF("[%d %d :%lld]\n",i,j,dp[i][j]);
}
dp[i][i]=(fsp(2,i*(i-1ll)/2ll)-sum+MOD)%MOD;
// PF("[%d %d :%lld]\n",i,i,dp[i][i]);
}
for(int i=1;i<=n;i++)
PF("%lld\n",dp[n][i]);
}