繁华模拟赛 Vicent坐电梯


/*
n<=5000
­这样就不能用O(n)的转移了,而是要用O(1)
的转移。
­注意我们每次的转移都来自一个连续的区间,
而且我们是求和
­区间求和?
­前缀和!
­sum[step][i]表示f[step][1~i]的和
­还是以B下侧为例
­ f[step][i]=sum[step-1][i-1]+sum[step-1][k]-sum[step-1][i]

*/
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 6000; const int MOD = 1000000007; int f[MAXN][MAXN] = {{0}}; int n, a, b, k; inline int getnum() { char c; int ans = 0; bool flag = false; while ((c = getchar()) == ' ' || c == '\r' || c == '\n'); if (c == '-') flag = true; else ans = c - '0'; while ((c = getchar()) >= '0' && c <= '9') ans = ans * 10 + c - '0'; return ans * (flag ? -1 : 1); } inline void add(int &a, int b) { ll tmp = (ll)a + b; if (tmp >= MOD) a = (int)(tmp - MOD); else if (tmp < 0) a = (int)(tmp + MOD); else a = (int)tmp; } int main() { freopen("lift.in", "r", stdin); freopen("lift.out", "w", stdout); n = getnum(); a = getnum(); b = getnum(); k = getnum(); if (fabs(a - b) - 1 == 0) { printf("0\n"); return 0; } for (int i = a; i <= n; i++) f[0][i] = 1; for (int step = 1; step <= k; step++) for (int i = 1; i <= n; i++) if (i == b) f[step][i] = f[step][i - 1]; else { f[step][i] = f[step][i - 1]; if (i < b) { int x = (b + i) / 2; if ((b + i) % 2 == 0) x--; add(f[step][i], f[step - 1][x]); add(f[step][i], -f[step - 1][i]); add(f[step][i], f[step - 1][i - 1]); } else { int x = (b + i) / 2; add(f[step][i], f[step - 1][n]); add(f[step][i], -f[step - 1][x]); add(f[step][i], -f[step - 1][i]); add(f[step][i], f[step - 1][i - 1]); } } printf("%d\n", f[k][n]); }

 

posted @ 2016-09-24 23:17  ACforever  阅读(296)  评论(0编辑  收藏  举报