版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/88387172
Description
在Byteland一共有n个城市,编号依次为1到n,它们之间计划修建n(n-1)/2条单向道路,对于任意两个不同的点i和j,在它们之间有且仅有一条单向道路,方向要么是i到j,要么是j到i。换句话说,这是一个n个点的竞赛图。Byteasar居住在1号城市,他希望从1号城市出发,沿着单向道路不重复地访问一些城市,使得访问的城市数尽可能多。请写一个程序,帮助Byteasar计算有多少种道路修建方式,使得从1号点出发的最长简单路径经过点数恰好为k,由于答案可能很大,请对P取模输出
Solution
竞赛图缩点后是一条链,最长路就是 以及后面的连通分量的大小之和。所以可以直接枚举 所在的连通分量大小和后面有多少个点,这样前面就有 个点,设 为 个点的竞赛图个数,那么前后的方案数分别为 和 。最难算的是有 个点的竞赛图缩点后变成一块的方案数,这个用到的是图计数中常用的容斥思想,枚举 所在连通分量大小,减去不合法方案,即
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=2010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,mod,C[Maxn][Maxn],f[Maxn],g[Maxn],h[Maxn],ans[Maxn],fac[Maxn];
int Pow(int x,int y)
{
if(!y)return 1;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
void upd(int&x,int y){x+=y;if(x>=mod)x-=mod;}
void pre()
{
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;
}
for(int i=0;i<=n;i++)h[i]=Pow(2,i*(i-1)/2);
g[1]=1,g[2]=0;
for(int i=3;i<=n;i++)
{
g[i]=h[i];
for(int j=1;j<i;j++)
g[i]=(g[i]-(LL)C[i][j]*h[i-j]%mod*g[j]%mod+mod)%mod;
}
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=(LL)fac[i-1]*i%mod;
}
int main()
{
n=read(),mod=read();
pre();
for(int i=1;i<=n;i++)
for(int j=0;i+j<=n;j++)
upd(ans[i+j],(LL)g[i]*C[n-1][i-1]%mod*h[j]%mod*C[n-i][j]%mod*h[n-i-j]%mod);
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}