【题意】给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;
}