[SRM613~] TaroCheckers
一定要注意Topcoder的提交机制
Solution
这道题思维比较巧妙。 一看就基本知道是一个Dp题。
首先转换一下,用列而不是行来设第一维的状态,因为每列只有放或不放两种状态。行的受力情况很复杂,这里啊
那么对于每一列,到了要分配Left
的时候我们再把前面的列分配过来。
到Right
的时候,我们就反其道而行之,把Right贮存下来,然后之后每一个格子都考虑要不要分配一次。
这样Dp状态就显而易见:\(Dp[i][j][k]\)表示前i
列中有j
列空余k
个Right
没有处理的方案数。
然后就比较容易写出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的更多相关文章
随机推荐
- eclipse提速02 - eclipse.ini优化
给eclipse执行jvm.它可以让你使用自己的jdk,而不是系统环境变量所指定的jdk -vm /path/to/your/java 使用最新的jdk来运行eclipse.使用最新的jdk要好很多. ...
- Java泛型的主要用途
1.泛型的主要用途就是代替各种类型,作为一个笼统的整体类型代替,也就是代替参数,不论是传入参数还是返回参数.都可以用泛型来代替. 如dao操作类的增删改查操作,因为传入参数的类型不同,但基本都是相同接 ...
- paramiko连接sshd使用的hostkey
1.sshd的hostkey设置: cat /etc/ssh/sshd_config 里面有rsa/dsa/ecdsa/ed25519 2.查看paramiko的keys选择顺序,如图所示 3.由以上 ...
- POJ3255 Roadblocks 【次短路】
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7760 Accepted: 2848 Descri ...
- RxJava系列之中的一个 初识Rxjava
1.简单介绍 基础知识 响应式代码的基本组成部分是Observables和Subscribers(事实上Observer才是最小的构建块,但实践中使用最多的是Subscriber.由于Subscrib ...
- 用户代码未处理 UpdateException
无法更新 EntitySet"Project_project",由于它有一个 DefiningQuery.而 <ModificationFunctionMapping> ...
- awk基本使用方法简单介绍
之前说过sed, 今天来说awk, 它也是一个文本处理器. 是linux下的一个命令, 比sed更强大. 搞linux开发, 尤其是后台开发, 这个命令差点儿必需要用到. awk这三个字母分别代表其三 ...
- STM32通过调用库函数进行编程
1.调用库函数编程和直接配置寄存器编程的差别: 2.CMSIS标准: 3.STM32库函数的组织: 4.程序例举: 调用库函数实现通过USART发送数据(26个大写的英文字母) 首先:在主函数部分先要 ...
- 2 TypeScript--Hello World
安装好TypeScript后,我们来完成第一个页面--Hello World 新建index.html文件: <!DOCTYPE html> <html> <head&g ...
- 发布Java桌面程序
我拿了一份桌面工具的开源代码,修修改改,在elipse上运行,感觉良好,但到了发布应用程序,就傻眼了.我居然不知道咋发布! 呵呵,不愧是Java小白! 如果是微软阵营,直接就编译成exe了.但java ...