1. 程式人生 > >連在一起的幻想鄉

連在一起的幻想鄉

題目大意:求nn個點的無向簡單連通圖邊數平方的和,n2000n\le2000。 題解: 考慮dp,設h0(n),h1(n),h2(n)h_0(n),h_1(n),h_2(n)分別表示所有nn個點無向簡單圖的邊數的00次,11次,22次方和,記m=(n2)m=\binom n2,易知: h0(n)=2mh1(n)=m2m1,h2(n)=i=1mi2(mi)=m(m+1)2m2h_0(n)=2^m\\h_1(n)=m2^{m-1},\\h_2(n)=\sum_{i=1}^{m}i^2\binom mi=m(m+1)2^{m-2}

(n)=m2m1,h2(n)=i=1mi2(im)=m(m+1)2m2 最後一個可以考慮對某個函式F(x)=(1+x)mF(x)=(1+x)^m求導乘以x,再求導然後乘以x,然後令x=1即可;事實上可以推廣到hk(n)h_k(n)的情況。 令f0(n),f1(n),f2(n)f_0(n),f_1(n),f_2(n)表示nn個點無向簡單連通圖的邊數的00次,11次,22次方和,則: fk(n)=hk(n)i=1n1(n1i1)j=0k(kj)fjhkjf_k(n)=h_k(n)-\sum_{i=1}^{n-1}\binom {n-1}{i-1}\sum_{j=0}^k\binom kj f_jh_{k-j}
這個也可以推廣到fk(n)f_k(n)的情況。 複雜度O(n2)O(n^2)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 2010
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" " #define ln <<endl using namespace std; int c[N][N],m[N],f0[N],f1[N],f2[N],h0[N],h1[N],h2[N],mod; inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; } int main() { int n;scanf("%d%d",&n,&mod);rep(i,1,n) m[i]=i*(i-1)/2; rep(i,1,n) h0[i]=fast_pow(2,m[i]),(i>1?h1[i]=(lint)m[i]*fast_pow(2,m[i]-1)%mod:0), (i>2?h2[i]=m[i]*(m[i]+1ll)%mod*fast_pow(2,m[i]-2)%mod:0); h1[1]=0,h2[1]=0,h2[2]=1,f0[1]=1,f1[1]=0,f2[1]=0;rep(i,0,n) c[i][0]=1; rep(i,1,n) rep(j,1,i) c[i][j]=c[i-1][j]+c[i-1][j-1],(c[i][j]>=mod?c[i][j]-=mod:0); rep(i,2,n) { lint w0=0,w1=0,w2=0; rep(j,1,i-1) w0+=(lint)c[i-1][j-1]*f0[j]%mod*h0[i-j]%mod, w1+=((lint)f1[j]*h0[i-j]+(lint)f0[j]*h1[i-j])%mod*c[i-1][j-1]%mod, w2+=((lint)f2[j]*h0[i-j]+2ll*f1[j]*h1[i-j]+(lint)f0[j]*h2[i-j])%mod*c[i-1][j-1]%mod; f0[i]=h0[i]-(int)(w0%mod),(f0[i]<0?f0[i]+=mod:0), f1[i]=h1[i]-(int)(w1%mod),(f1[i]<0?f1[i]+=mod:0), f2[i]=h2[i]-(int)(w2%mod),(f2[i]<0?f2[i]+=mod:0); } return !printf("%d\n",f2[n]); }