博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
51nod1835 完全图
阅读量:5150 次
发布时间:2019-06-13

本文共 1181 字,大约阅读时间需要 3 分钟。

题意:输入n,m(n,m<500),问有n的点且联通块为m个的图有多少

题解:

dp[i][j]代表取前i个形成j个联通块的个数

第i个单独考虑,可以枚举联通块的大小K:[1, i-j+1]
要保证枚举的时候方案不会重复,那么不能写作c(i, k)
这样dp[i1][j]和dp[i2][j]会有重复的部分
所以这里固定下来第i个是必须要取的
那么方案数就是c(i-1, k-1)
所以可以得到递推式
for(int k=1;k<=i-j+1;k++)
dp[i][j] += c(i-1, k-1)*dp[i-k][j-1]*dp[k][1];
dp[k][1]要单独计算,它的意义是k个数形成一个联通块的方案数:
dp[k][1] = 2^(k*(k-1)/2);
for(int i=2;i<=k;i++) dp[k][1] -= dp[k][i];
注意题目要求至少一条边,所以当m==1时,答案要减1

要预处理

#include 
#define ll long long#define maxn 510using namespace std;const ll mod = 998244353;ll c[maxn][maxn], n, m, dp[maxn][maxn];void init(){ for(ll i=0;i<=500;i++){ c[i][0] = c[i][i] = 1; for(ll j=1;j
>= 1; } return ans;}int main(){ init(); scanf("%lld%lld", &n, &m); for(ll i=1;i<=n;i++){ for(ll j=2;j<=i;j++) for(ll k=1;k<=i-j+1;k++) dp[i][j] = (dp[i][j]+c[i-1][k-1]*dp[i-k][j-1]%mod*dp[k][1]%mod)%mod; dp[i][1] = f(2, (i*(i-1)/2)); for(ll j=2;j<=i;j++) dp[i][1] = (dp[i][1]+mod-dp[i][j])%mod; } if(m == 1) printf("%lld\n", dp[n][1]-1); else printf("%lld\n", dp[n][m]); return 0;}

 

转载于:https://www.cnblogs.com/Noevon/p/8406280.html

你可能感兴趣的文章
HTML5简单入门系列(四)
查看>>
AndroidStudio快捷键
查看>>
实现字符串反转
查看>>
转载:《TypeScript 中文入门教程》 5、命名空间和模块
查看>>
苹果开发中常用英语单词
查看>>
[USACO 1.4.3]等差数列
查看>>
Shader Overview
查看>>
Reveal 配置与使用
查看>>
Java中反射的学习与理解(一)
查看>>
nginx配置socket服务
查看>>
C语言初学 俩数相除问题
查看>>
B/S和C/S架构的区别
查看>>
[Java] Java record
查看>>
jQuery - 控制元素显示、隐藏、切换、滑动的方法
查看>>
postgresql学习文档
查看>>
Struts2返回JSON数据的具体应用范例
查看>>
js深度克隆对象、数组
查看>>
c++ 贪吃蛇
查看>>
socket阻塞与非阻塞,同步与异步
查看>>
图论求割点模板
查看>>