【题意】给n层楼,开始的时候人在a,层,并且在b层不能停下来。当从x层去y层时要满足|x-y|<|x-b|?求执行k次的方案数。

【解题方法】

dp[i][j]代表第i次当前停在j层的方案数。

sum[i][j]代表第i次停留在j层的方案数的前缀。

当a<b时,此时所有的x不会超过b,当第i次停在j层,第i-1次肯定在[0,(b+j-1)/2],左端点不难想到,右端点推导过程:


设第i-1次停在x层,则第i层所有大于x小于b的点都可以取,我们只考虑小于x的点,则x-j<=b-x-1,

整理得:   x<=(b+j-1)/2; 所以转移方程为:dp[i][j]=(sum[i-1][(j+b-1)/2]-dp[i-1][j]+mod)%mod;

当a>b时,同理得dp[i][j]=((sum[i-1][n]-sum[i-1][(j+b)/2]+mod)%mod-dp[i-1][j]+mod)%mod;

【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5010;
const int mod=1e9+7;
int dp[maxn][maxn];//dp[i][j]代表第i次当前停在j层的方案数
int sum[maxn][maxn];//sum[i][j]代表第i次停留在j层的方案数的前缀
int n,a,b,k;//
void init(){
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
}
ll ans;
//处理前缀
void getsum(int x){
    for(int i=1; i<=n; i++){
        sum[x][i]=(sum[x][i-1]+dp[x][i])%mod;
    }
}
int main()
{
    cin>>n>>a>>b>>k;
    ans=0;
    dp[0][a]=1;//INIT.
    if(a<b){
        getsum(0);
        for(int i=1; i<=k; i++){
            for(int j=1; j<b; j++){
                dp[i][j]=(sum[i-1][(j+b-1)/2]-dp[i-1][j]+mod)%mod;
            }
            getsum(i);
        }
    }
    else{
        getsum(0);
        for(int i=1; i<=k; i++){
            for(int j=b+1; j<=n; j++){
                dp[i][j]=((sum[i-1][n]-sum[i-1][(j+b)/2]+mod)%mod-dp[i-1][j]+mod)%mod;
            }
            getsum(i);
        }
    }
    for(int i=1; i<=n; i++) ans=(ans+dp[k][i])%mod;
    cout<<ans<<endl;
}