[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<bits/stdc++.h>
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 <int> Left, vector <int> 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