【JZOJ5061】【GDOI2017第二轮模拟day1】最长路径

来源:互联网 发布:windows api文档 编辑:程序博客网 时间:2024/05/16 07:18

Description

在Byteland 一共有n 个城市,编号依次为1 到n,它们之间计划修建n(n-1)/2条单向道路,对于任意两个不同的点i 和j,在它们之间有且仅有一条单向道路,方向要么是i 到j,要么是j 到i。换句话说,这是一个n 个点的竞赛图。
Byteasar 居住在1 号城市,他希望从1 号城市出发,沿着单向道路不重复地访问一些城市,使得访问的城市数尽可能多。
请写一个程序,帮助Byteasar 计算有多少种道路修建方式,使得从1 号点出发的最长简单路径经过点数恰好为k,由于答案可能很大,请对P 取模输出。

Data Constraint

这里写图片描述

Solution

对于不太喜欢用脑子的我来说,10分钟打出前60分后走人……
但现在是时候正面杠这道题了……
根据某位大牛的理论,竞赛图有以下性质:
1、竞赛途中必存在一条哈比顿路径。
2、若把在同一个强连通分量的点合并,并然会形成一条链的形式,即不会产生分叉。
别问我怎么证明,理解不到,就背到。
我们设出f[i]表示i个点时竞赛图的方案,g[i]表示i个点时全图构成一个强连通分量的方案。

f[n]=2n(n1)/2

g[n]=f[n]i=1n1g[i]f[ni]Cin

那么我们现在设i表示1所在的强连通分量的大小,j表示1之后有多少个点。
ans[i+j]=g[i]Ci1n1f[j]f[nij]Cjnij

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const ll maxn=2e3+5;ll f[maxn],g[maxn],c[maxn][maxn],ans[maxn];ll n,mo,i,t,j,k,l,x,y,z;ll mi(ll y){    if (y==1) return 2;    ll t=mi(y/2);    if (y%2) return t*t%mo*2%mo;return t*t%mo;}int main(){    freopen("path.in","r",stdin);freopen("path.out","w",stdout);    scanf("%lld%lld",&n,&mo);    c[0][0]=1;    for (i=1;i<=n;i++){        c[i][0]=1;        for (j=1;j<=i;j++)            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;    }    f[0]=g[0]=f[1]=g[1]=1;    for (i=1;i<=n;i++){        if (i>1)f[i]=g[i]=mi(i*(i-1)/2);        for (j=1;j<i;j++)            g[i]-=g[j]*f[i-j]%mo*c[i][j]%mo;        g[i]=(g[i]%mo+mo)%mo;    }    for (i=1;i<=n;i++){        for (j=0;j<=n-i;j++)            ans[i+j]+=c[n-1][i-1]*c[n-i][j]%mo*g[i]%mo*f[j]%mo*f[n-i-j]%mo;    }    for (i=1;i<=n;i++)        ans[i]%=mo,printf("%lld\n",ans[i]);}
1 0