电梯
问题描述
无所事事的Cinzo决定用坐电梯的方式来打发时间。他住在一个N层的房子中,最底下为1层,最高处为N层。他从他家所在的第A层出发,并决定连续坐K次电梯。
但由于迷信的缘故,B在中国被视为是不幸运的,所以整座楼并没有第B层。也是因为这个原因,如果Cinzo想从第X层出发到达第Y层,他希望Y能满足|X - Y| < |X - B|。
每次电梯到达后,Cinzo都会将电梯所到的层数记录在小本子上;K次电梯都坐完后,他将得到一个长度为K的数列。现在,Cinzo想知道,他可能写出多少个不同的数列?
输入格式(lift.in)
一行四个整数,N,A,B,K,分别代表电梯的层数,Cinzo最初的位置,不幸运的层数,以及乘坐电梯的次数。
输出格式(lift.out)
一个整数,代表不同的数列数。(结果对1000,000,007取模)
样例输入
5 2 4 2
样例输出
2
数据范围与约束
对于20%的数据,N<=10, K<=5;
对于60%的数据,N,K<=100;
对于100%的数据,N,K<=5000。
思路:
优化的dp。为什么可以优化那?
时间上的优化:因为每一次递推改变的是一个范围内的值,所以能用差值维护。
空间上的优化:每一步仅与他的上一步有关,能用滚动数组。
#include<iostream> #include<queue> #include<math.h> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define M 1000000007 #define LL long long int n,a,b,k; LL f[2][5005],ans; int l[5005],r[5005]; int main() { freopen("lift.in", "r", stdin); freopen("lift.out", "w", stdout); scanf("%d%d%d%d",&n,&a,&b,&k); f[0][a]=1; int e=0,g=1; for(int i=1;i<=n;i++) { int dis=abs(i-b); l[i]=max(1,i-dis+1); r[i]=min(n,i+dis-1); } for(int i=1;i<=k;i++) { for(int j=1;j<=n;j++) f[g][j]=0; for(int j=1;j<=n;j++) (f[g][l[j]]+=f[e][j])%=M,(f[g][r[j]+1]-=f[e][j])%=M; for(int j=1;j<=n;j++) (f[g][j]+=f[g][j-1])%=M; for(int j=1;j<=n;j++) f[g][j]-=f[e][j]; swap(e,g); } for(int j=1;j<=n;j++) (ans+=f[e][j])%=M; ans=(ans+M)%M; cout<<ans; return 0; }