ATB180F Unbranched 学习笔记
ATB180F Unbranched 学习笔记
题意简述
求 \(n\) 个点,\(m\) 条边且满足以下条件的无向图数量:
- 无自环。
- 每个点度数最多为 \(2\)。
- 连通块大小的最大值恰为 \(L\)。
点有标号。答案对 \(10^9+7\) 取模。
\(2\le n\le 300\),\(1\le m,L\le n\)。
做法解析
每个点度数最多为 \(2\) 就是在说这个图是由若干链或环构成的。
你先考虑,如果是“连通块大小的最大值最多为 \(L\)”,那你会不会做?我们用DP解决这个问题。设 \(f_{i,j}\) 为用了 \(i\) 个点,\(j\) 条边之后最大连通块大小不大于 \(L\) 的方案数。那么这个东西是比较好转移的,显然使用填表法,我们枚举新加入的一个连通块大小 \(k\)。显然 \(f_{i,j}\) 可以从 \(f_{i-k,j-k}\)(即加入了一条点数为 \(k\) 的环)和 \(f_{i-k,j-k+1}\)(即加入链)。
如果你加入了一条 \(k\) 个点的链,你实际上是从 \(n-i+k\) 各点里面选出 \(k\) 个点作为一条链,显然方案是 \(A_{n-i+k}^{k}\)……的吗?注意,举个例子,对于两条链 \(\{3,4,5\}\),\(\{6,7,8\}\),如果两个方案唯一的区别在于加入这两者的先后顺序不一样,它们按理来说应该算一个方案。所以我们每次转移时钦定当前编号最小的点必须被选中,这样的话这种情形就不会被算重。另外,注意长度大于 \(1\) 的链会两两同构,所以我们还要除以二。
环的情况同理。注意长度大于 \(2\) 的环也会两两同构,所以也要除以二。
你发现条件里有一个“恰好为 \(L\)”,我们可以将它转化为“最多为 \(L\)”的方案数减去“最多为 \(L-1\)”的方案数。这样这题就做完了。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
using namespace omodint;
using mint=m107;
const int MaxN=3e2+5;
mint facr[MaxN],finv[MaxN];
using namespace omathe;
int N,M,L;mint dp[MaxN][MaxN];
mint solve(int n,int m,int lim){
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
dp[i][j]=0;
for(int k=1;k<=min({lim,i,j+1});k++)dp[i][j]+=dp[i-k][j+1-k]*Arra(n-i+k-1,k-1)*k/(k==1?1:2);
for(int k=2;k<=min({lim,i,j});k++)dp[i][j]+=dp[i-k][j-k]*Arra(n-i+k-1,k-1)/(k==2?1:2);
}
}
return dp[n][m];
}
int main(){
readis(N,M,L);premwork(N);
writi(miti(solve(N,M,L)-solve(N,M,L-1)));
return 0;
}
反思总结
经典套路:“恰好”转成两个“最多为”之差。
这道题没有那一大坨熔池系数的原因是这真的只是“‘恰好’转成两个‘最多为’之差”,与二项式反演和那个不等于“至少”的“钦定”无关。
浙公网安备 33010602011771号