ゴリ押ししてしまった…。
https://yukicoder.me/problems/no/2917
問題
正整数Nが与えられる。
N頂点のラベル付き木Tと、その部分誘導グラフT'のうち木である者の対(T,T')は何通りか。
解法
T'のサイズを総当たりしよう。
仮にそのサイズをSとする。
残り(N-S)頂点をいくつかの根付き木にし、各根付き木の頂点を、S個の頂点のどこからか選ぶことを考える。
各木の組み合わせはケーリーの公式で求めるとして、他に根付き木の個数と使用済み頂点数の2値でDPするとO(N^2)かかる。
Sも総当たりすると全体O(N^3)。
Nが大きめで若干厳しいが、128bit値を使い除算を減らすとどうにか通る。
int N; ll mo; ll comb(int P_,int Q_) { static const int N_=1020; static ll C_[N_][N_]; if(C_[0][0]==0) { int i,j; FOR(i,N_) C_[i][0]=C_[i][i]=1; for(i=1;i<N_;i++) for(j=1;j<i;j++) C_[i][j]=(C_[i-1][j-1]+C_[i-1][j])%mo; } if(P_<0 || P_>N_ || Q_<0 || Q_>P_) return 0; return C_[P_][Q_]; } ll modpow(ll a, ll n = mo-2) { ll r=1;a%=mo; while(n) r=r*((n%2)?a:1)%mo,a=a*a%mo,n>>=1; return r; } __int128 dp[1010]; ll C[2020]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>mo; C[1]=C[2]=1; for(i=3;i<=1000;i++) C[i]=modpow(i,i-2); ll ret=0; for(i=1;i<=N;i++) { ZERO(dp); dp[i]=C[i]*comb(N,i)%mo; for(j=i;j<N;j++) { dp[j]%=mo; for(x=1;j+x<=N;x++) (dp[j+x]+=dp[j]*comb(N-j-1,x-1)*C[x]*x*i); } ret+=dp[N]%mo; } cout<<ret%mo<<endl; }
まとめ
O(N^2√N)解法はまだ理解できてない。