Codeforces Round #313 (Div. 1) C. Gerald and Giant Chess

来源:互联网 发布:vb自动处理网页弹框 编辑:程序博客网 时间:2024/06/06 09:09

Link

http://codeforces.com/contest/559/problem/C

Description

n×m 的网格,要从(1,1)走到(n,m),只能沿着行或者列增加的方向走,又其中有 k 个地方不能走,问路径数目。

Data scope

1n105
1m105
1k2000

Solution

 X   S    X   X   T   X 

显然是容斥原理问题,为此我们把禁止走的格子标号。并且设f(i1i2...ip)表示走i1,i2,...,ip这些禁止格子的路径数。
 1   S    2   3   T   4 

那么:
result=f(null)f(1)f(2)f(3)f(4)+f(12)+f(13)+f(14)+f(23)+f(24)+f(34)f(123)f(124)f(134)f(234)+f(1234)

f(i1i2...ip)的求法并不复杂,它是一系列组合数的乘积,这里不赘述。
距离解决问题的障碍是项太多。一共有2k项,但是应该认识到是有些项的路径是不存在的。
比如 f(14) 就是不可能的,但是 f(23) 就是可以的。原因嘛……
这就启发我们对每一个点计算一个值dp[u],表示经过这个点之后要乘的组合数的和。
dp[u]=calc(u,T)vxux,vyuycalc(u,v)dp[v]

result=calc(S,T)calc(S,u)dp[u]

Evaluation

Not bad…

Code

#include <bits/stdc++.h>const int MAXK = 2000 + 5;const int MOD = int(1e9) + 7;std::pair<int, int> ban[MAXK];#define fst first#define sec secondstd::vector<int> g[MAXK];long long dp[MAXK];const int MAXN = int(2e5) + 5;long long fac[MAXN];long long inv_fac[MAXN];int n, m, k;void fac_table() {  fac[0] = 1;  for (int i = 1; i < MAXN; i++)    fac[i] = fac[i - 1] * i % MOD;  inv_fac[0] = 1;  inv_fac[1] = 1;  for (int i = 2; i < MAXN; i++)    inv_fac[i] = (MOD - MOD / i) * inv_fac[MOD % i] % MOD;  for (int i = 2; i < MAXN; i++)    inv_fac[i] = inv_fac[i] * inv_fac[i - 1] % MOD;  for (int i = 0; i < MAXN; i++)    assert(fac[i] * inv_fac[i] % MOD == 1);}long long pascal(int n, int m) {  return fac[n] * (inv_fac[m] * inv_fac[n - m] % MOD) % MOD;}long long calc(int x, int y, int p, int q) {  return pascal(p + q - x - y, p - x);}long long calc(int u) {  return calc(ban[u].fst, ban[u].sec, n, m);}long long calc(int u, int v) {  return calc(ban[u].fst, ban[u].sec, ban[v].fst, ban[v].sec);}int dfs(int u) {  if (dp[u] != -1)    return dp[u];  dp[u] = calc(u);  for (int i = 0; i < g[u].size(); i++) {    int v = g[u][i];    dp[u] = (dp[u] + calc(u, v) * (MOD - dfs(v)) % MOD) % MOD;  }  return dp[u];}int main() {  fac_table();  scanf("%d %d %d", &n, &m, &k);  for (int i = 0; i < k; i++) {    scanf("%d %d", &ban[i].fst, &ban[i].sec);  }  for (int i = 0; i < k; i++) {    for (int j = 0; j < k; j++) {      if (i == j)        continue;      if (ban[j].fst >= ban[i].fst && ban[j].sec >= ban[i].sec)        g[i].push_back(j);    }  }  memset(dp, -1, sizeof(dp));  long long res = calc(1, 1, n, m);  for (int i = 0; i < k; i++) {    res = (res + calc(1, 1, ban[i].fst, ban[i].sec) * (MOD - dfs(i))) % MOD;  }  printf("%d\n", (int) res);  return 0;}
0 0
原创粉丝点击