题目传送门
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的情况单独讨论
#include
#include
#include
#include
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);
}