Codeforces 814E An unavoidable detour for home dp

An unavoidable detour for home

首先明确的一点是从前往后dp, 因为有dis[ i + 1 ] >= dis[ i ] 这个条件存在。

然后我先就考虑将顶点一个一个填进去, 但是发现需要开六七个50乘起来的数组才能维护。

我发现有一个条件还没有利用起来, 就是每个点到 1 的最短路唯一, 我们考虑将到 1 距离一样的点

一起考虑去更新dp。

dp[ o ][ i ][ j ] 表示处理到完了o, 还有 i 个顶点需要 1 的度数, 还有 j 个顶点需要 2 的度数。

对于dp[ o ][ i ][ j ] 需要i + 2 * j 个当前这个段连接才能转移。

way1[ i ][ j ] 表示有 i 个顶点需要 1 的度数, 有 j 个顶点需要 2 的度数, 填满这样的段的方案数。

way2[ l ][ r ][ i ][ j ] 表示考虑l - r作为一个整体的一段, 每个都向之前一段连条边,

段内相互连边之后有 i 个顶点需要 1 的度数, 有 j 个顶点需要 2 的度数的方案数。

然后就可以转移啦。 有点恶心就是了。 

#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 51;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

int n, d[N];
int way1[N][N];
int way2[N][N][N][N];
int dp[N][N][N];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &d[i]);
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= n; j++) {
            int ret = 1, tot = i + 2 * j, num1 = i, num2 = j;
            while(num2--) ret = 1LL * tot * (tot - 1) / 2 * ret % mod, tot -= 2;
            while(num1--) ret = 1LL * ret * tot % mod, tot--;
            way1[i][j] = ret;
        }
    }
    for(int l = 1; l <= n; l++) {
        for(int r = l; r <= n; r++) {
            int len = r - l + 1;
            for(int i = l; i <= r; i++) {
                for(int j = 0; j <= len; j++) {
                    for(int k = 0; j + k <= len; k++) {
                        dp[i][j][k] = 0;
                    }
                }
            }
            if(d[l] == 2) dp[l][1][0] = 1;
            else dp[l][0][1] = 1;
            for(int o = l; o < r; o++) {
                for(int i = 0; i <= len; i++) {
                    for(int j = 0; i + j <= len; j++) {
                        if(!dp[o][i][j]) continue;
                        if(d[o + 1] == 2) {

                            add(dp[o + 1][i + 1][j], dp[o][i][j]);

                            if(i) add(dp[o + 1][i - 1][j], 1LL * dp[o][i][j] * i % mod);
                            if(j) add(dp[o + 1][i + 1][j - 1], 1LL * dp[o][i][j] * j % mod);
                        } else {
                            add(dp[o + 1][i][j + 1], dp[o][i][j]);


                            if(i) add(dp[o + 1][i][j], 1LL * dp[o][i][j] * i % mod);
                            if(j) add(dp[o + 1][i + 2][j - 1], 1LL * dp[o][i][j] * j % mod);

                            if(i >= 2) add(dp[o + 1][i - 2][j], 1LL * dp[o][i][j] * (i * (i - 1) / 2) % mod);
                            if(j >= 2) add(dp[o + 1][i + 2][j - 2], 1LL * dp[o][i][j] * (j * (j - 1) / 2) % mod);
                            if(i && j) add(dp[o + 1][i][j - 1], 1LL * dp[o][i][j] * (i * j) % mod);
                        }
                    }
                }
            }
            for(int i = 0; i <= len; i++) {
                for(int j = 0; i + j <= len; j++) {
                    way2[l][r][i][j] = dp[r][i][j];
                }
            }
        }
    }
    memset(dp, 0, sizeof(dp));
    if(d[1] == 2) {
        for(int i = 0; i <= 2; i++) {
            for(int j = 0; i + j <= 2; j++) {
                add(dp[3][i][j], way2[2][3][i][j]);
            }
        }
    } else {
        for(int i = 0; i <= 3; i++) {
            for(int j = 0; i + j <= 3; j++) {
                add(dp[4][i][j], way2[2][4][i][j]);
            }
        }
    }
    for(int o = 3; o < n; o++) {
        for(int i = 0; i <= o; i++) {
            for(int j = 0; i + j <= o; j++) {
                if(!dp[o][i][j]) continue;
                if(!i && !j) continue;
                int len = i + 2 * j, l = o + 1, r = o + len;
                if(o > n) continue;
                for(int u = 0; u <= len; u++) {
                    for(int v = 0; u + v <= len; v++) {
                        add(dp[r][u][v], 1LL * way2[l][r][u][v] * way1[i][j] % mod * dp[o][i][j] % mod);
                    }
                }
            }
        }
    }
    printf("%d
", dp[n][0][0]);
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/11091234.html