电梯

问题描述

无所事事的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;
} 

 

posted @ 2017-07-27 15:32  浪矢-CL  阅读(196)  评论(0编辑  收藏  举报