[SRM613~] TaroCheckers

一定要注意Topcoder的提交机制

Links: 原题地址 Vjudge

Solution

这道题思维比较巧妙。 一看就基本知道是一个Dp题。

首先转换一下,用列而不是行来设第一维的状态,因为每列只有放或不放两种状态。行的受力情况很复杂,这里啊

那么对于每一列,到了要分配Left的时候我们再把前面的列分配过来。

Right的时候,我们就反其道而行之,把Right贮存下来,然后之后每一个格子都考虑要不要分配一次。

这样Dp状态就显而易见:\(Dp[i][j][k]\)表示前i列中有j列空余kRight没有处理的方案数。

然后就比较容易写出dp方程.下面是废话:

先分类。这一列可以对Left Right造成影响. 也可以不造成影响(放在没用的地方或完全不让放)

因为Left,Right对状态影响很大,所以分成两个式子。

notice:在考虑问题的时候中间问题的中间态如果不是很重要的话,整体都可以略过

具体见代码

Code

#include
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
    char ch = getchar();
    int x = 0, flag = 1;
    for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + 48);
}

const int Maxn = 59, Maxm = 209, Mod = 1e9 + 7;
class TaroCheckers {
    public:
        LL C[Maxm * 10][Maxm * 10], dp[Maxm][Maxm][Maxn], fac[Maxm * 10];
        LL L[Maxm], R[Maxm];
        void calcMath(LL m) {
            C[0][0] = fac[0] = 1;
            rep (i, 1, m) fac[i] = fac[i - 1] * i % Mod;
            rep (i, 1, m) {
                C[i][0] = C[i][i] = 1;
                rep (j, 1, i - 1) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % Mod;
            }
        }
        int getNumber(vector  Left, vector  Right, int m) {
            LL n = (LL)Left.size();
            calcMath(n + m); clar(dp, 0); clar(L, 0), clar(R, 0);
            rep (i, 0, n - 1) ++L[Left[i]], ++R[m - Right[i] + 1];
            dp[0][0][0] = 1; LL res = 0;
            rep (i, 0, m - 1) {
                LL cnt1 = L[i + 1], cnt2 = R[i + 1];
                rep (j, 0, i)
                    rep (k, 0, n)
                        if (dp[i][j][k]) {
                            if (j + 1 >= cnt1) (dp[i + 1][j + 1 - cnt1][k + cnt2] += dp[i][j][k] * C[j + 1][cnt1] % Mod * fac[cnt1] % Mod) %= Mod; 
                            if (j >= cnt1) (dp[i + 1][j - cnt1][k + cnt2] += dp[i][j][k] * C[j][cnt1] % Mod * fac[cnt1] * (res - cnt2 + 1) % Mod) %= Mod; 
                            if (j >= cnt1 && k + cnt2 - 1 >= 0) (dp[i + 1][j - cnt1][k + cnt2 - 1] += dp[i][j][k] * C[j][cnt1] % Mod * fac[cnt1] % Mod * (k + cnt2) % Mod) %= Mod;  
                        }
                res += cnt1 - cnt2;
            }

            return dp[m][0][0];
        }
};

转载于:https://www.cnblogs.com/qrsikno/p/10159822.html

你可能感兴趣的:([SRM613~] TaroCheckers)