题意:有n层楼,你现在在a层,禁地在b层,每次的移动如下:从x层移动到y层,必须满足|x-y|<|x-b|。问移动恰好k次的方案数。
解析:设dp[i][j]为移动了i次位于j层的方案数。则对于dp[i-1][j],
dp[i][每个从j层可以移动到的位置] += dp[i-1][j]。
采用类似BIT区间增减的方法标记对应的端点,进行状态转移。
[code]:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
const LL MOD = 1e9+7;
const int maxn = 5005;
int n,a,b,k;
LL dp[maxn],S[maxn];
int main(){
int i,j,t;
scanf("%d%d%d%d",&n,&a,&b,&k);
memset(dp,0,sizeof(dp));
dp[a] = 1;
memset(S,0,sizeof(S));
for(i = 1;i <= k;i++){
for(j = 1;j <= n;j++){
if(j < b){
S[b] = ((S[b]-dp[j])%MOD+MOD)%MOD;
S[j] = ((S[j]-dp[j])%MOD+MOD)%MOD;
t = max(1,2*j-b+1);
S[t] = (S[t]+dp[j])%MOD;
S[j+1] = (S[j+1]+dp[j])%MOD;
}else{
S[b+1] = (S[b+1]+dp[j])%MOD;
S[j+1] = (S[j+1]+dp[j])%MOD;
S[j] = ((S[j]-dp[j])%MOD+MOD)%MOD;
t = min(n+1,2*j-b);
S[t] = ((S[t]-dp[j])%MOD+MOD)%MOD;
}
}
LL sum = 0;
for(j = 1;j <= n;j++){
sum = (sum+S[j])%MOD;
dp[j] = sum;
S[j] = 0;
}
}
LL ans = 0;
for(j = 1;j <= n;j++) ans = (ans + dp[j])%MOD;
printf("%I64d\n",ans);
return 0;
}