[AtCoder Beginner Contest 281][G. Farthest City]
和 CF1657E 的做法十分相似
题目链接:G - Farthest City
题目大意:问有多少个 个点的无向连通图满足,若设 到 的最短路距离为 ,则 严格大于其它所有的 。输出方案数对 取模。
考虑最短路的值一定是连续的,那么若最短路为 的点数有 个,且 ,则方案数可以计算
其中,。 的含义为最短路为 的点是从最短路为 的点连接过来的,那么对于每个这样的点,他可以选择上一层的任意一个非空子集进行连接。 的含义则是,对当前层的所有点,两两之间可以任意连接,对应可连接的边数为 ,于是会有 的系数。
考虑背包,按最短路的值从小到大一批批安排当前点,那么有一个初始的 DP 想法,就是令 表示当前已经安排了 个点,目前最短路的最大值为 ,对应点的个数为 的方案数,那么枚举最短路值为 的点的数量 ,可以转移到 ,转移系数为 。但是直接这样做是 的。
发现转移系数与 无关,所以这一维可以直接省去,于是 DP 方式就变成,设 表示当前已经安排了 个点,且目前最短路最大的点数为 的方案数,那么同样枚举下一层的点数 ,就能转移到 ,转移系数为 。初始值设 ,最后答案即为 。
#include<bits/stdc++.h>
using namespace std;
#define N 510
#define LL long long
int n,MOD,f[N][N],c[N][N],p[N*N],ans;
LL qow(LL x,LL y){return y?(y&1?x*qow(x,y-1)%MOD:qow(x*x%MOD,y/2)):1;}
int main()
{
scanf("%d%d",&n,&MOD);
p[0]=c[0][0]=1;
for(int i=1;i<=n;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
for(int i=1;i<=n*n;i++)p[i]=2ll*p[i-1]%MOD;
f[1][1]=1;
for(int i=1;i<n;i++)
for(int j=1;j<=i;j++)if(f[i][j])
for(int k=1;i+k<n;k++)
f[i+k][k]=(f[i+k][k]+1ll*f[i][j]*c[n-i-1][k]%MOD*qow(p[j]+MOD-1,k)%MOD*p[k*(k-1)/2]%MOD)%MOD;
for(int j=1;j<=n-1;j++)
ans=(ans+1ll*f[n-1][j]*(p[j]+MOD-1)%MOD)%MOD;
printf("%d\n",ans);
}
时间复杂度为 ,预处理了 的值稍微进行了点常数优化。实际上是可以通过 预处理每个 的值把复杂度降到 的,但是既然能过就不优化了。╮(╯▽╰)╭
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】