引
A T AT AT 的题面大多数情况下都挺人性的
解法
考虑分析三个限制:
−
-
− 图中无自环 : 对于构造图时特判大小为
1
1
1 的环
−
-
− 每个点度数最多为
2
2
2 : 仔细想想,这个限制翻译过来就是图中每一个连通块是一个 链 或者 环 , 不可能是 团 或者 树
−
-
− 所有连通块最多恰好有
L
L
L 个点
:
:
: 没什么好说的,
D
P
DP
DP 的时候限制一下或者装进
D
P
DP
DP 状态里转移
设计状态 :
f
i
,
j
:
选
i
个点,构成的图中联通块的大小不超过
j
的合法方案数
f_{i,j} :选i个点,构成的图中联通块的大小不超过j的合法方案数
fi,j:选i个点,构成的图中联通块的大小不超过j的合法方案数
那么
a
n
s
=
f
n
,
m
ans=f_{n,m}
ans=fn,m
状态转移 :
分别讨论加入的新的联通块是链或环的情况即可
链 :
f
i
,
j
←
∑
k
=
1
min
{
i
,
j
+
1
,
L
}
f
i
−
k
,
j
−
(
k
−
1
)
∗
C
k
−
1
n
−
(
i
−
k
)
−
1
∗
k
!
2
注意
k
=
1
的情况单独讨论
f_{i,j} \gets \sum_{k=1}^{\min\{i,j+1,L\}}f_{i-k,j-(k-1)} *C^{n-(i-k)-1}_{k-1} *\frac{k!}{2}\\ 注意k=1的情况单独讨论
fi,j←k=1∑min{i,j+1,L}fi−k,j−(k−1)∗Ck−1n−(i−k)−1∗2k!注意k=1的情况单独讨论
环 :
f
i
,
j
←
∑
k
=
2
m
i
n
(
i
,
j
,
L
)
f
i
−
k
,
j
−
k
∗
C
k
−
1
n
−
(
i
−
k
)
−
1
∗
(
k
−
1
)
!
2
一样的,注意
k
=
2
的情况单独讨论
f_{i,j} \gets \sum_{k=2}^{min(i,j,L)} f_{i-k,j-k}*C^{n-(i-k)-1}_{k-1} * \frac{(k-1)!}{2}\\ 一样的,注意k=2的情况单独讨论
fi,j←k=2∑min(i,j,L)fi−k,j−k∗Ck−1n−(i−k)−1∗2(k−1)!一样的,注意k=2的情况单独讨论
Code :
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 307,M=300,INF=0x3f3f3f3f;
const ll mod=1e9+7 ,inv2=500000004;
int n,m,L;
ll ans;
ll f[N][N],fac[N],ifac[N];
void init() {
for(int i=0;i<=n;i++) for(int j=0;j<=m;j++)
f[i][j]=0;
}
ll qpow(ll ba,ll pow) {
ll res=1; while(pow) {
if(pow&1) res=res*ba%mod;
ba=ba*ba%mod,pow>>=1;
} return res;
}
void pre() {
fac[0]=1; for(int i=1;i<=M;i++) fac[i]=fac[i-1]*i%mod;
ifac[M]=qpow(fac[M],mod-2); for(int i=M;i;i--) ifac[i-1]=ifac[i]*i%mod;
}
ll C(ll x,ll y) { return fac[x]*ifac[y]%mod*ifac[x-y]%mod; }
void work(int lim) {
f[0][0]=1;
for(int i=1;i<=n;i++) {
for(int j=0;j<=m;j++) {
for(int k=1;k<=min(j+1,min(lim,i));k++) {
f[i][j]=(f[i][j]+f[i-k][j-(k-1)]*C(n-(i-k)-1,k-1)%mod*(k>1?fac[k]*inv2%mod:1)%mod)%mod;
if(k>1) f[i][j]=(f[i][j]+f[i-k][j-k]*C(n-(i-k)-1,k-1)%mod*(k>2?fac[k-1]*inv2%mod:1)%mod)%mod;
}
}
}
}
int main() {
scanf("%d%d%d",&n,&m,&L);
pre();
work(L),ans=f[n][m];
init(),work(L-1);
// printf("%lld\n",ans);
printf("%lld\n",((ans-f[n][m])%mod+mod)%mod);
}