一定要注意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];
}
};

[SRM613~] TaroCheckers的更多相关文章

随机推荐

  1. html5摇一摇代码优化

    首先对DeviceMotionEvent进行优化: 去除没用的代码,又一次封装DeviceMotionEven if(window.DeviceMotionEvent) { var speed = 2 ...

  2. Office EXCEL 中单元格怎么打斜线

    右击单元格,然后设置单元格格式,然后添加需要的边框     注意里面的文字有讲究,比如我要右上角显示Value,左下角显示Payload,则需要先输一堆空格,然后输入Value,把Value挤到右边去 ...

  3. GCC编译动态和静态链接库例子

    我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而是 ...

  4. 我的kindle书单

    刚刚入手kindle,希望能够持续阅读,不断进步. 列下书单,记录我的阅读足迹,更希望园友若有好书多多推荐,互相交流. # keep updating ... 我的kindle书单 book name ...

  5. 电子设计省赛--PID

    //2014年4月17日 //2014年6月20日入"未完毕"(未完毕) //2014年6月21日 一開始还以为是多难的算法.事实上就是个渣渣. 当然PID实践中应该会非常难. 另 ...

  6. 矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推)

    https://www.vijos.org/p/1067 非常easy推出递推式f[n] = f[n-1]+f[n-2]+......+f[n-k]. 构造矩阵的方法:构造一个k*k的矩阵.当中右上角 ...

  7. 连接虚拟机的SQLServer

    1.IP可以互相PING通 2.Telnet发现端口没有放开,防火墙新建入账规则开放端口 成功..

  8. while语句字符串的基本操作

    1,编码:对现在通用文字编码成计算机文字,便于储存,传递,交流. 最早的计算机编码是ACSII美国人创建的,包含英文字母,数字,以及特殊符号.总共是128个码位:2**7,因为计算机的底层只能识别:& ...

  9. Why was 80 Chosen as the Default HTTP Port and 443 as the Default HTTPS Port?

    https://www.howtogeek.com/233383/why-was-80-chosen-as-the-default-http-port-and-443-as-the-default-h ...

  10. C++明确规定,不能获取构造函数和析构函数的地址

    C++标准明确规定,不能获取构造函数和析构函数的地址,因此也无法形成指向他们的成员函数指针. 指向成员函数的指针可以,指向构造函数析构函数的不行.因为构造函数和析构函数都是没有返回值的,无法声明一个没 ...