Not Too Close 题解

题号太长就不放在题目里了,给个链接

题意简述

一张无向图有 $n(2\le n\le30)$ 个点,已知它的所有边权都是 $1$。求满足点 $1$ 和点 $2$ 之间的最短路为给定的 $D(1\le D<n)$ 的无向图的数量。

题目分析

考虑在每个图上将到点 $1$ 的距离相同的点看作同一层。那么我们得到每一层的点只会与上一层、下一层及同层的点有连边(连边的两个点跨度不会超过 $1$ 层,否则距离点 $1$ 更远的那个点到 $1$ 的最短路可以更短,矛盾)。由于边是无向边,不妨只在距离点 $1$ 更近的那个点统计跨层的边。

设 $f_{i,j,k}$ 为共 $j$ 个与点 $1$ 距离不超过 $i$ 的点,且共 $k$ 个点与点 $1$ 的距离正好为 $i$ 的方案数(多记 $k$ 一维是为了方便扩展状态)。对于每个状态的扩展,枚举下一层点的个数 $l$。则方案数可分为三部分:

  • 下一层的点具体是哪些:$\binom{n-j-1}{l-[i+1=D]}$
  • 下一层内点互相之间的连边情况:$2^{\binom l2}$
  • 该层与下一层之间连边情况:$(2^k-1)^l$

回到原问题,我们只计算前 $D$ 层的 $f$。而对于每一个 $f_{D,j,k}$,未确定的点互相之间可以任意连,但都只能连第 $D$ 层确定的点,因此方案数为 $2^{k(n-j)+\binom{n-j}2}$。

总时间复杂度为 $O(n^4)$,$n\le30$ 绰绰有余。

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,d,mod,pow2[45010],f[160][160][160],C[160][160],ans;
int main()
{
    scanf("%d%d%d",&n,&d,&mod);
    pow2[0]=1;
    for(int i=1;i<=n*n;i++)
        pow2[i]=(pow2[i-1]<<1)%mod;//预处理 2 的幂
    for(int i=0;i<=n;i++)
        C[i][0]=C[i][i]=1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;//组合数
    f[0][1][1]=1;
    for(int i=0;i<d;i++)
        for(int j=i;j<=n;j++)
            for(int k=1;k<=j-i+1;k++)
                if(f[i][j][k])
                    for(int tmp=f[i][j][k],l=1;l<=n-j-d+i+1;l++)
                        tmp=1ll*tmp*(pow2[k]-1)%mod,f[i+1][j+l][l]=(f[i+1][j+l][l]+1ll*tmp*pow2[l*(l-1)/2]%mod*C[n-j-1][l-(i+1==d)]%mod)%mod;//上文提到的三种情况乘法原理乘在一起就行了
    for(int i=d;i<=n;i++)
        for(int k=1;k<=n;k++)
            ans=(ans+1ll*f[d][i][k]*pow2[(n-i)*(n-i-1)/2+(n-i)*k]%mod)%mod;//第 D 层统计答案
    printf("%d",ans);
    return 0;
}
posted @ 2023-08-10 20:48  Hadtsti  阅读(2)  评论(0编辑  收藏  举报  来源