版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82810572
传送门:bzoj5219
题解
竞赛图性质:
- 必然存在一条哈密尔顿路径
- 缩点之后按拓扑序形成一条“链”
由竞赛图性质得到从点1出发的最长路径上点数等于1所在 点数+拓扑序在1(链中靠后)的 的点的总数。
表示有 个节点的竞赛图的个数,显然: 。
表示有
个节点的竞赛图强连通分量,考虑枚举拓扑序最小的
进行容斥:
初始 ,其余递推得到。
表示则点1出发最长路径为 的方案数。枚举1所在 点数以及链中靠后的总点数:
组合数线性递推预处理即可。
代码
#include<bits/stdc++.h>
#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;
}