Not Too Close 题解

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

题意简述

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

题目分析

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

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

  • 下一层的点具体是哪些:(nj1l[i+1=D])
  • 下一层内点互相之间的连边情况:2(l2)
  • 该层与下一层之间连边情况:(2k1)l

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

总时间复杂度为 O(n4)n30 绰绰有余。

代码实现

#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 @   Hadtsti  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示