连在一起的幻想乡 - dp

题目大意:求 n n n个点的无向简单连通图边数平方的和, n ≤ 2000 n\le2000 n2000
题解:
考虑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)=m2m1,h2(n)=i=1mi2(im)=m(m+1)2m2
最后一个可以考虑对某个函数 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=1n1(i1n1)j=0k(jk)fjhkj
这个也可以推广到 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]);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值