题解:AT_yahoo_procon2019_final_e Espionage
题目分析
题意相当于求该图的哈密顿回路个数,这是一个
考虑 DP,尝试划分子问题,直接观察上面建出来的图就可以发现去切完全图显然不如切层,也就是说按层来划分比按栋来划分更有前途。
那么就扫层,假设当前扫到了第
为了后续更方便的实现,我们先给这个哈密顿回路定向,那么现在就是切出来许多有向路径,每条路径的入端和出端一定都在第
因此可以设
考虑转移到
现在再来考虑
那么现在就能从
Code
#include<bits/stdc++.h>
using namespace std;
//
const int maxn=200+10;
const int mod=1e9+7;
inline int add(const int x,const int y){return x+y>=mod?x+y-mod:x+y;}
inline int sub(const int x,const int y){return x-y<0?x-y+mod:x-y;}
inline int Pow(int x,int y){
int s=1;
for(;y;x=1ll*x*x%mod,y>>=1)if(y&1)s=1ll*s*x%mod;
return s;
}
int n,m,ans;
int fac[maxn],ifac[maxn];
inline int C(int n,int m){return n<0||m<0||n<m?0:1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
void init(int n){
fac[0]=ifac[0]=1;
for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
ifac[n]=Pow(fac[n],mod-2);
for(int i=n-1;i>=1;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}
inline int calc(int n,int k){return !n&&!k?1:1ll*fac[n]*C(n-1,k-1)%mod*ifac[k]%mod;}
struct Matrix{
int mat[maxn][maxn];
Matrix(){memset(mat,0,sizeof(mat));}
}f,a;
inline Matrix operator * (const Matrix &a,const Matrix &b){
Matrix c;
for(int k=0;k<=n;k++)for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)c.mat[i][j]=add(c.mat[i][j],1ll*a.mat[i][k]*b.mat[k][j]%mod);
return c;
}
inline Matrix Pow(Matrix x,int y){
Matrix s;
for(int i=0;i<=n;i++)s.mat[i][i]=1;
for(;y;x=x*x,y>>=1)if(y&1)s=s*x;
return s;
}
int main(){
cin>>n>>m;
init(n);
for(int i=0;2*i<=n;i++){ //上一行i条链,这一行n-2i个孤立点
for(int j=1;j<=n-i;j++){ //合并为j条链
int sum=0;
for(int k=0;k<=n-2*i&&k<=j;k++){ //二项式反演
if(k&1)sum=sub(sum,1ll*C(n-2*i,k)*calc(n-i-k,j-k)%mod);
else sum=add(sum,1ll*C(n-2*i,k)*calc(n-i-k,j-k)%mod);
}
a.mat[i][j]=sum;
}
}
f.mat[0][0]=1;
f=f*Pow(a,m-1);
ans=0;
for(int i=1;i<=n;i++)ans=add(ans,1ll*f.mat[0][i]*fac[n-i-1]%mod);
cout<<ans<<'\n';
return 0;
}