题目大意:求
n
n
n个点的无向简单连通图边数平方的和,
n
≤
2000
n\le2000
n≤2000。
题解:
考虑dp,设
h
0
(
n
)
,
h
1
(
n
)
,
h
2
(
n
)
h_0(n),h_1(n),h_2(n)
h0(n),h1(n),h2(n)分别表示所有
n
n
n个点无向简单图的边数的
0
0
0次,
1
1
1次,
2
2
2次方和,记
m
=
(
n
2
)
m=\binom n2
m=(2n),易知:
h
0
(
n
)
=
2
m
h
1
(
n
)
=
m
2
m
−
1
,
h
2
(
n
)
=
∑
i
=
1
m
i
2
(
m
i
)
=
m
(
m
+
1
)
2
m
−
2
h_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}
h0(n)=2mh1(n)=m2m−1,h2(n)=i=1∑mi2(im)=m(m+1)2m−2
最后一个可以考虑对某个函数
F
(
x
)
=
(
1
+
x
)
m
F(x)=(1+x)^m
F(x)=(1+x)m求导乘以x,再求导然后乘以x,然后令x=1即可;事实上可以推广到
h
k
(
n
)
h_k(n)
hk(n)的情况。
令
f
0
(
n
)
,
f
1
(
n
)
,
f
2
(
n
)
f_0(n),f_1(n),f_2(n)
f0(n),f1(n),f2(n)表示
n
n
n个点无向简单连通图的边数的
0
0
0次,
1
1
1次,
2
2
2次方和,则:
f
k
(
n
)
=
h
k
(
n
)
−
∑
i
=
1
n
−
1
(
n
−
1
i
−
1
)
∑
j
=
0
k
(
k
j
)
f
j
h
k
−
j
f_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)=hk(n)−i=1∑n−1(i−1n−1)j=0∑k(jk)fjhk−j
这个也可以推广到
f
k
(
n
)
f_k(n)
fk(n)的情况。
复杂度
O
(
n
2
)
O(n^2)
O(n2)。
#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]);
}