ABC281G Farthest City

本文介绍了一道编号为ABC281G的问题解决思路,该问题要求求解特定条件下简单无向连通图的数量,并给出了一种使用分层图DP的方法。通过状态转移方程,最终实现了O(n^3)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ABC281G Farthest City

题目大意

给你两个整数 n n n m m m,求一个包含 n n n个点的简单无向连通图的个数:

  • 对于所有点 u = 2 , … , n − 1 u=2,\dots,n-1 u=2,,n1 u u u n n n的距离严格小于 1 1 1 n n n的距离

输出答案模 m m m后的值。


题解

d i d_i di表示 1 1 1 i i i的最短距离,则当 i i i j j j之间有边时,若 d i ≤ d j d_i\leq d_j didj,则一定满足 d j − d i ≤ 1 d_j-d_i\leq1 djdi1。我们可以使用分层图 D P DP DP来解决。

f i , j f_{i,j} fi,j表示当前用了 i i i个点,最后一层有 j j j个点的方案数,则转移式为

f i , j = ∑ l = 1 i − j f i − j , l × ( 2 l − 1 ) j × 2 j ( j − 1 ) 2 × C n − i + j − 1 j f_{i,j}=\sum\limits_{l=1}^{i-j}f_{i-j,l}\times(2^l-1)^j\times2^{\frac{j(j-1)}{2}}\times C_{n-i+j-1}^j fi,j=l=1ijfij,l×(2l1)j×22j(j1)×Cni+j1j

其中 l l l表示上一层的点的个数。

首先这一层的每一个点都可以和上一层的点连接。因为上一层有 l l l个点,每个点可以连或不连,再减去所有点都不连的情况,每个点有 ( 2 l − 1 ) (2^l-1) (2l1)种情况能与上一层的点连通,那么 j j j个点就有 ( 2 l − 1 ) j (2^l-1)^j (2l1)j种情况。

对于这一层,任意两个点之间都可以连边或不连边,也就是有 2 j ( j − 1 ) 2 2^{\frac{j(j-1)}{2}} 22j(j1)种情况。

当然,每一个点是不同的,所以对于这一层,我们是从剩下的 ( n − i + j − 1 ) (n-i+j-1) (ni+j1)个点(不包括 n n n,所以要减 1 1 1)中选 j j j个点,因此还要乘上 C n − i + j − 1 j C_{n-i+j-1}^j Cni+j1j

注意最后 n n n是独立的一层,要特判。

由此得到转移式。枚举状态 O ( n 2 ) O(n^2) O(n2),每次转移 O ( n ) O(n) O(n),总时间复杂度为 O ( n 3 ) O(n^3) O(n3)。注意在求 a b a^b ab这类数的时候要提前预处理,不要使用快速幂,否则会 T L E TLE TLE

code

#include<bits/stdc++.h>
using namespace std;
int n;
long long mod,ans,tw[250005],yh[505][505],v[505][505],f[505][505];
int main()
{
	scanf("%d%lld",&n,&mod);
	for(int i=0;i<=n;i++){
		yh[i][0]=yh[i][i]=1;
		for(int j=1;j<i;j++){
			yh[i][j]=(yh[i-1][j]+yh[i-1][j-1])%mod;
		}
	}
	tw[0]=1;
	for(int i=1;i<=n*n;i++) tw[i]=tw[i-1]*2%mod;
	for(int i=0;i<=n;i++){
		v[i][0]=1;
		long long tmp=(tw[i]-1+mod)%mod;
		for(int j=1;j<=n;j++){
			v[i][j]=v[i][j-1]*tmp%mod;
		}
	}
	f[1][1]=1;
	for(int i=2;i<=n-1;i++){
		for(int j=1;j<i;j++){
			for(int l=1;l<=i-j;l++){
				f[i][j]=(f[i][j]+f[i-j][l]*v[l][j]%mod*tw[j*(j-1)/2]%mod*yh[n-i+j-1][j]%mod)%mod;
			}
		}
	}
	for(int i=1;i<n-1;i++){
		ans=(ans+f[n-1][i]*(tw[i]-1)%mod)%mod;
	}
	printf("%lld",ans);
	return 0;
}

参考博客:https://blog.youkuaiyun.com/weixin_46700592/article/details/128273233

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值