Solution
以前做过一道题是这样的
- 给定
n∗m
的网格图和
k
个点,求不定过某些点从
(1,1) 走到 (n,m) 的方案数。
这个的话直接
O(k2)
DP就好了。
这道题也差不多,因为电池的衰减只有
O(log2s)
种,所以DP时记录一下当前经过的点的个数就好了。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 101010;
const int M = 2020;
const int MOD = 1000000007;
typedef long long ll;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
int n, m, k, s, lim, ans;
struct Point {
int x, y;
Point (int _x = 0, int _y = 0):x(_x), y(_y) {}
inline friend bool operator <(const Point &a, const Point &b) {
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
};
Point a[M];
int fac[N << 1], inv[N << 1];
int dp[N][100];
inline int Pow(int a, int b) {
int c = 1;
while (b) {
if (b & 1) c = (ll)c * a % MOD;
b >>= 1; a = (ll)a * a % MOD;
}
return c;
}
inline int Inv(int x) {
return Pow(x, MOD - 2);
}
inline int C(int n, int m) {
return (ll)fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
inline int Calc(int n, int m) {
return C(n + m, n);
}
int main(void) {
read(n); read(m); read(k); read(s);
inv[1] = 1; lim = 25;
for (int i = 2; i <= 200000; i++)
inv[i] = (ll)(MOD - MOD / i) * inv[MOD % i] % MOD;
fac[0] = inv[0] = 1;
for (int i = 1; i <= 200000; i++) {
fac[i] = (ll)fac[i - 1] * i % MOD;
inv[i] = (ll)inv[i - 1] * inv[i] % MOD;
}
for (int i = 1; i <= k; i++) {
read(a[i].x); read(a[i].y);
}
sort(a + 1, a + k + 1);
if (a[k].x == n && a[k].y == m) s -= s / 2;
else a[++k] = Point(n, m);
if (a[1].x != 1 || a[1].y != 1) {
s *= 2; a[++k] = Point(1, 1);
}
sort(a + 1, a + k + 1);
dp[1][0] = 1;
for (int i = 2; i <= k; i++) {
dp[i][1] = Calc(a[i].x - 1, a[i].y - 1);
for (int d = 2; d <= lim; d++) {
for (int j = 1; j < i; j++) {
if (a[j].y > a[i].y) continue;
dp[i][d] += (ll)dp[j][d - 1] * Calc(a[i].x - a[j].x, a[i].y - a[j].y) % MOD;
dp[i][d] -= (ll)dp[j][d] * Calc(a[i].x - a[j].x, a[i].y - a[j].y) % MOD;
dp[i][d] = (dp[i][d] % MOD + MOD) % MOD;
}
}
}
ans = 0;
for (int i = 1; i <= lim; i++) {
s -= s / 2;
ans = ans + (ll)(dp[k][i] - dp[k][i + 1] + MOD) * s % MOD;
ans %= MOD;
}
cout << (ll)ans * Inv(Calc(n - 1, m - 1)) % MOD << endl;
return 0;
}