NC214840. [NOIP2020]微信步数(walk)
描述
输入描述
第一行两个用单个空格分隔的整数 n,k。分别表示路线步数与场地维数。接下来一行 k 个用单个空格分隔的整数 wi,表示场地大小。接下来 n 行每行两个用单个空格分隔的整数 ci,di,依次表示每一步的方向,具体意义见题目描述。
输出描述
仅一行一个整数表示答案。答案可能很大,你只需要输出其对 109 + 7 取模后的值。若小 C 的计划会使得他在某一天在场地中永远走不出来,则输出一行一个整数 -1。
示例1
输入:
3 2 3 3 1 1 2 -1 1 1
输出:
21
说明:
示例2
输入:
5 4 6 8 6 5 3 1 2 1 1 1 2 1 2 -1
输出:
10265
C++ 解法, 执行用时: 71ms, 内存消耗: 4352K, 提交时间: 2022-04-22 09:02:06
#include <bits/stdc++.h> #define rep(i, a, b) for (int i = (a); i <= int(b); i++) #define per(i, a, b) for (int i = (a); i >= int(b); i--) using namespace std; typedef long long ll; const int maxn = 5e5, mod = 1e9 + 7; int n, k, w[10], c[maxn + 5], d[maxn + 5], dt[10], res, S[11][11], inv[12]; struct foo{ int z[10], l[10], r[10]; void reset() { memset(z, 0, k << 2); memset(l, 0, k << 2); memset(r, 0, k << 2); } foo(){ reset(); } int walk(int c, int d){ z[c] += d; if (z[c] < l[c] || z[c] > r[c]){ l[c] = min(l[c], z[c]); r[c] = max(r[c], z[c]); return d; } return 0; } } F, B; inline void red(int &x){ x += x >> 31 & mod; } void prework(int n){ S[0][0] = 1; rep(i, 1, n) rep(j, 1, i){ S[i][j] = (S[i - 1][j - 1] + ll(S[i - 1][j]) * j) % mod; } inv[1] = 1; rep(i, 2, n + 1){ inv[i] = ll(mod - mod / i) * inv[mod % i] % mod; } } int calc(int k, int n){ int s = 0, c = 1; rep(i, 0, k){ c = ll(c) * max(0, n - i) % mod; s = (s + ll(c) * inv[i + 1] % mod * S[k][i]) % mod; } return s; } int work(int a[]){ int lim = mod; rep(i, 0, k - 1) if (dt[i]){ lim = min(lim, (a[i] + dt[i] - 1) / dt[i]); } int dp[11] = { 1 }; rep(i, 0, k - 1){ per(j, i, 0){ dp[j + 1] = (dp[j + 1] + ll(mod - dt[i]) * dp[j]) % mod; dp[j] = ll(a[i]) * dp[j] % mod; } } int res = 0; rep(i, 0, k){ res = (res + ll(dp[i]) * calc(i, lim)) % mod; } return res; } int main(){ // freopen("walk.in", "r", stdin); // freopen("walk.out", "w", stdout); scanf("%d %d", &n, &k); prework(k); rep(i, 0, k - 1){ scanf("%d", &w[i]); } rep(i, 1, n){ scanf("%d %d", &c[i], &d[i]), c[i]--; if (F.walk(c[i], d[i]) && F.r[c[i]] - F.l[c[i]] <= w[c[i]]) { int x = 1; rep(j, 0, k - 1) if (j != c[i]){ x = ll(x) * max(0, w[j] - F.r[j] + F.l[j]) % mod; } res = (res + ll(i) * x) % mod; } } rep(i, 1, n) if (F.z[c[i]] < 0){ d[i] = -d[i]; } rep(i, 0, k - 1) if (F.z[i] < 0){ F.z[i] = -F.z[i]; swap(F.l[i], F.r[i]); F.l[i] = -F.l[i]; F.r[i] = -F.r[i]; } B = F; bool chk = true; rep(i, 0, k - 1){ dt[i] = B.z[i]; chk &= dt[i] == 0; } if (chk){ bool ok = false; rep(i, 0, k - 1){ ok |= B.r[i] - B.l[i] >= w[i]; } printf("%d\n", ok ? res : -1); exit(0); } int a[10] = {}; rep(i, 1, n){ if (F.walk(c[i], d[i]) && F.r[c[i]] - F.l[c[i]] <= w[c[i]]){ bool ok = true; rep(j, 0, k - 1) if (j != c[i]){ ok &= w[j] - F.r[j] + F.l[j] > 0; } if (!ok){ continue; } rep(j, 0, k - 1) if (j != c[i]){ a[j] = w[j] - F.r[j] + F.l[j]; } a[c[i]] = w[c[i]] - F.r[c[i]] + F.l[c[i]] + 1, res = (res + ll(i) * work(a)) % mod; a[c[i]] = w[c[i]] - F.r[c[i]] + F.l[c[i]], res = (res + ll(mod - i) * work(a)) % mod; } } rep(i, 0, k - 1){ a[i] = max(0, w[i] - B.r[i] + B.l[i]); } res = (res + ll(n) * work(a)) % mod; printf("%d\n", res); return 0; }