【Atcoder】 [ABC133F] Colorful Tree

题目链接

Atcoder方向
Luogu方向

题目解法

超妙的 dp 题
考虑把题目转化为二分图匹配
假设每对点下面都有一条黑线,那么怪异度即为跨过黑线的总数
考虑令 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 为到 i i i 对,前面有 j j j 对未匹配,当前怪异度为 k k k 的方案数
考虑转移:
i , j i,j i,j 匹配,则不会新增未匹配对数, d p [ i ] [ j ] [ k ] + = d p [ i − 1 ] [ j ] [ k − 2 j ] dp[i][j][k]+=dp[i-1][j][k-2j] dp[i][j][k]+=dp[i1][j][k2j],其中 k − 2 j k-2j k2j 的含义是前面 2 j 2j 2j 个未匹配会跨越当前的黑线,也可以理解为价值提前计算
i i i 和右部点匹配 或 j j j 和左部点匹配,则不会新增未匹配对数, d p [ i ] [ j ] [ k ] + = 2 j ∗ d p [ i − 1 ] [ j ] [ k − 2 j ] dp[i][j][k]+=2j*dp[i-1][j][k-2j] dp[i][j][k]+=2jdp[i1][j][k2j]
i , j i,j i,j 都不匹配,则会新增一对未匹配点, d p [ i ] [ j ] [ k ] + = d p [ i − 1 ] [ j − 1 ] [ k − 2 j ] dp[i][j][k]+=dp[i-1][j-1][k-2j] dp[i][j][k]+=dp[i1][j1][k2j]
i , j i,j i,j 都与之前未匹配的匹配,则会减少一对未匹配点, d p [ i ] [ j ] [ k ] + = ( j + 1 ) ∗ ( j + 1 ) ∗ d p [ i − 1 ] [ j + 1 ] [ k − 2 j ] dp[i][j][k]+=(j+1)*(j+1)*dp[i-1][j+1][k-2j] dp[i][j][k]+=(j+1)(j+1)dp[i1][j+1][k2j]

时间复杂度 O ( n 2 k ) O(n^2k) O(n2k)

#include 
using namespace std;
const int N(60),P(1e9+7);
int n,m,dp[N][N][N*N];
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
int main(){
    n=read(),m=read();
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++)
            for(int k=2*j;k<=m;k++){
                int add=(1ll*(2*j+1)*dp[i-1][j][k-2*j]+1ll*(j+1)*(j+1)*dp[i-1][j+1][k-2*j])%P;
                if(j>0) add=(add+dp[i-1][j-1][k-2*j])%P;
                (dp[i][j][k]+=add)%=P;
            }
    // cout<
    printf("%d",dp[n][0][m]);
    return 0;
}
/*
dp[i][j][k]:二分图上到第i个点,有j个点未匹配,当前怪异度为k的方案数
*/

你可能感兴趣的:(Atcoder,算法)