[ABC281G] Farthest City

Problem Statement

You are given positive integers $N$ and $M$.
Find the number, modulo $M$, of simple connected undirected graphs with $N$ vertices numbered $1, \dots, N$ that satisfy the following condition.

  • For every $u = 2, \dots, N-1$, the shortest distance from vertex $1$ to vertex $u$ is strictly smaller than the shortest distance from vertex $1$ to vertex $N$.

Here, the shortest distance from vertex $u$ to vertex $v$ is the minimum number of edges in a simple path connecting vertices $u$ and $v$.
Two graphs are considered different if and only if there are two vertices $u$ and $v$ that are connected by an edge in exactly one of those graphs.

Constraints

  • $3 \leq N \leq 500$
  • $10^8 \leq M \leq 10^9$
  • $N$ and $M$ are integers.

Input

The input is given from Standard Input in the following format:

$N$ $M$

Output

Print the answer.


Sample Input 1

4 1000000000

Sample Output 1

8

Sample Input 2

3 100000000

Sample Output 2

1

Sample Input 3

500 987654321

Sample Output 3

610860515

Be sure to find the number modulo $M$.

首先有一种生成树叫做最短路树(在本题可以理解成BFS树)。其实就是一棵树,保证根节点到点 \(x\) 的距离等于原图中根节点到点 \(x\) 的距离。发现 \(n\) 一定是单独占据了一层。考虑在树上一层一层去dp.

定义 \(dp_{i,j}\) 为已经填了 \(i\) 个数,最后一层有 \(j\) 个数的方案数。为了保证 \(n\) 在最后一层,在dp过程中假设只有 \(n-1\) 个数,最后才把点 \(n\) 加上去。枚举上一层有多少个数,如果有 \(k\) 个,那么考虑从 \(dp_{i-j,k}\) 中转移。明显只有相邻的层之间可以互相连边,不然不能保证最短路树的性质。在这一层的 \(j\) 个数可以任意和上一层的 \(k\) 个数连边,但是不可以一个都不连,方案数 \((2^k-1)^j\)。从剩余的 \(n-1-i+j\) 个数中要选出 \(j\) 个数,方案有 \(C_{n-1-i+j}^j\) 种。同时同一层的点互相连是没有影响的,方案乘上 \(2^{j\times (j-1)}\)。总结,

\[dp_{i,j}=\sum\limits_{k=1}^{i-j}dp_{i-j,k}\times (2^k-1)^j\times C_{n-1-i+j}^j\times 2^{j\times (j-1)} \]

最后统计答案时,当最后一层有 \(j\) 个,那么点 \(n\) 可以随便和这 \(j\) 个点连边,但也不能全部不连。所以答案为

\[\sum\limits_{j=1}^{n-1}dp_{n-1,j}\times(2^j-1) \]

为了保证 \(O(1)\) 转移,中要预处理出 \(pw_{i,j}\) 表示 \((2^i-1)^j\) 以及组合数。

#include<cstdio>
const int N=505;
int n,P,dp[N][N],f[N][N],pw[N][N],pw2[N*N],ans;//f[i][j]表示选了i个数,最后一层选了j个的方案数 
int main()
{
	scanf("%d%d",&n,&P);
	for(int i=pw2[0]=1;i<=n*n;i++)
		pw2[i]=(pw2[i-1]<<1)%P;
	for(int i=dp[0][0]=1;i<=n;i++)
	{
		dp[i][0]=dp[i][i]=1;
		for(int j=1;j<i;j++)
			dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%P;
	}
	for(int i=pw[0][0]=1;i<=n;i++)
	{
		int k=pw2[i]-1;
		for(int j=0,p=1;j<=n;j++,p=1LL*p*k%P)
			pw[i][j]=p;
	}
	f[1][1]=1;
//	printf("%d\n",f[4][1]);
	for(int i=2;i<n;i++)
	{
//		if(i==n)
//			printf("%d\n",i);
		for(int j=1;j<i;j++) 
			for(int k=1;k<=i-j;k++)
				(f[i][j]+=1LL*f[i-j][k]*dp[n-1-i+j][j]%P*pw[k][j]%P*pw2[j*(j-1)/2]%P)%=P;
	}
//	printf("%d\n",n-1);
//	for(int i=1;i<=n;i++)
//	{
//		printf("%d\n",i);
//		for(int j=1;j<i;j++)
//			printf("%d %d %d\n",i,j,f[i][j]);
//	}
	for(int j=1;j<n;j++)
		(ans+=1LL*(pw2[j]-1)*f[n-1][j]%P)%=P;
	printf("%d",ans);
}
posted @ 2022-12-12 17:20  灰鲭鲨  阅读(56)  评论(0编辑  收藏  举报