BZOJ 4005 [JLOI 2015] 骗我呢
首先,我们可以得到:每一行的数都是互不相同的,所以每一行都会有且仅有一个在 $[0, m]$ 的数没有出现。
我们可以考虑设 $Dp[i][j]$ 为处理完倒数 $i$ 行,倒数第 $i$ 行缺的数字是 $j$ 的方案数。
那么就有:
$$Dp[i][j] = \sum_{k=max(0,j-1)}^{m}Dp[i - 1][k]$$
自己画一画图就可以明白了,在这里就不解释了。毕竟 Gromah 太懒($ru\grave{o}$)
然后我们考虑把这个转移图画出来:
然后就是求这个图中从右上到左下的路径条数嘛。(每次只能往左或者是往右下或者是往下)
转化一下,实际上就是求这个东西:
从 $(0,0)$ 到 $(n*2+m+1,m+1)$,每次可以 $x+1,y-1$ 或者 $x+1,y+1$,并且不穿过 $y=0$ 和 $y=m+1$ 这两条直线的路径条数。
首先,全集是 ${n*2+m+1 \choose m+1}$,
然后我们算穿过 $y=0$ 的路径条数,既然穿过 $y=0$ 就必然经过 $y=-1$,于是我们让终点和 $y=m+2$ 这条直线沿着 $y=-1$ 翻转,
然后就可以算出 $(0,0)$ 到翻转之后的终点的路径条数。
于是还没完。还有那些先穿过 $y=0$ 再又穿过 $y=m+1$ 这条直线的路径我们要加回来。。。
于是又把坐标系沿着翻转之后的 $y=m+2$ (此时应该是 $y=-m-4$ 了)再次翻转。再统计答案。。。
直到方案为 $0$ 了为止。
计算穿过 $y=m+1$ 的路径条数同理。。。
我知道我语言表达能力及其低下,所以还是上代码好了。。。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 #define N 3000000 9 #define Mod 1000000007 10 11 int n, m, ans = 0; 12 int Fac[N + 1], Inv[N + 1]; 13 14 inline int power(int u, int v) 15 { 16 int res = 1; 17 for (; v; v >>= 1) 18 { 19 if (v & 1) res = (LL) res * u % Mod; 20 u = (LL) u * u % Mod; 21 } 22 return res; 23 } 24 25 inline void Prepare() 26 { 27 Fac[0] = Inv[0] = 1; 28 for (int i = 1; i <= N; i ++) 29 Fac[i] = (LL) Fac[i - 1] * i % Mod; 30 Inv[N] = power(Fac[N], Mod - 2); 31 for (int i = N - 1; i ; i --) 32 Inv[i] = (LL) Inv[i + 1] * (i + 1) % Mod; 33 } 34 35 inline int C(int u, int v) 36 { 37 if (u < 0 || v < 0 || u < v) return 0; 38 return (LL) Fac[u] * Inv[v] % Mod * Inv[u - v] % Mod; 39 } 40 41 inline int T(int u, int v) 42 { 43 if (u < abs(v)) return 0; 44 return C(u, u - abs(v) >> 1); 45 } 46 47 inline int Inc(int u, int v) 48 { 49 return u + v - (u + v >= Mod ? Mod : 0); 50 } 51 52 int main() 53 { 54 #ifndef ONLINE_JUDGE 55 freopen("4005.in", "r", stdin); 56 freopen("4005.out", "w", stdout); 57 #endif 58 59 Prepare(); 60 scanf("%d%d", &n, &m); 61 int x = n * 2 + m + 1; 62 ans = T(x, m + 1); 63 64 for (int y = m + 1, y_1 = -1, y_2 = m + 2; x >= abs(y); ) 65 { 66 y = 2 * y_1 - y; 67 y_2 = 2 * y_1 - y_2; 68 ans = Inc(ans, Mod - T(x, y)); 69 y = 2 * y_2 - y; 70 y_1 = 2 * y_2 - y_1; 71 ans = Inc(ans, T(x, y)); 72 } 73 74 for (int y = m + 1, y_1 = m + 2, y_2 = -1; x >= abs(y); ) 75 { 76 y = 2 * y_1 - y; 77 y_2 = 2 * y_1 - y_2; 78 ans = Inc(ans, Mod - T(x, y)); 79 y = 2 * y_2 - y; 80 y_1 = 2 * y_2 - y_1; 81 ans = Inc(ans, T(x, y)); 82 } 83 84 printf("%d\n", ans); 85 86 #ifndef ONLINE_JUDGE 87 fclose(stdin); 88 fclose(stdout); 89 #endif 90 return 0; 91 }