5219: [Lydsy2017省队十连测]最长路径
最长路径长度为(k)的图一定能分成(A)(包含(1),共(k)个点)和(B)两部分,(AB)间连边一定是(B)->(A);
(dp)一下,(dp[i][j])表示共(i)个点,最长路径长度为(j)的竞赛图个数;
(dp[i][j]=dp[j][j]*C_{i-1}^{j-1}*2^{(i-j)*(i-j-1)/2});
(dp[i][i]=2^{i*(i-1)/2}-sum_{j=1}^{i-1}dp[i][j]);
就是选出(j-1)个点与(1)构成(A),剩下(B)内部的边随便连;
(dp[i][i])的话用所有的减去不合法的就行了;
AC GET☆DAZE
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 2039
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,p,pw[N*N],C[N][N],dp[N][N];
void get_pw()
{
pw[0]=1;
for(int a=1,b=n*(n-1)/2;a<=b;a++) pw[a]=pw[a-1]*2%p;
}
void get_C()
{
for(int a=0;a<=n;a++) C[a][0]=1;
for(int a=1;a<=n;a++)
{
for(int b=1;b<=a;b++)
{
C[a][b]=(C[a-1][b]+C[a-1][b-1])%p;
}
}
}
int main()
{
scanf("%d%d",&n,&p);
get_pw(),get_C();
for(int a=1;a<=n;a++)
{
dp[a][1]=pw[(a-1)*(a-2)/2];
for(int b=2;b<a;b++)
{
dp[a][b]=(ll)dp[b][b]*C[a-1][b-1]%p*pw[(a-b)*(a-b-1)/2]%p;
}
dp[a][a]=pw[a*(a-1)/2];
for(int b=1;b<a;b++) (dp[a][a]-=dp[a][b])%=p;
(dp[a][a]+=p)%=p;
}
for(int a=1;a<=n;a++)
{
printf("%d
",dp[n][a]);
}
return 0;
}