题目大意大概是 有一个N层高的楼,你乘坐电梯去任意一个楼层 一共要坐K次,有一个楼层为B的那层不能去, 你当前在A这层。乘坐有个限制,当你在X层 ,乘坐到Y层,要满足|X-Y| <|X-B|。
每坐一次你记录一个当前层数,坐完K次过后就会有一个序列,问你乘坐K次过后 会有多少种 不同的序列。对 10^9+7 取模
输入 是N,A,B,K 范围是都是1-5000
首先 很容易想到DP,那么状态想一想 应该也很清楚,DP[i][j], 表示第I次 坐电梯,到J层 时一共有多少方案数。 这种定义状态很容易想到
那么接下来就考虑复杂度,首先枚举 乘坐次数 ,然后 枚举 每一层,第I次乘坐 到J层方案数 可以由I-1次的某一层 转到,这个某一层由题目的限制条件可以算出来,
这样的话是n^3的效率,但是想到可以求前缀和,所以可以降低到N^2来做
注意 我为了清楚方便 还区分了 当 a<b 和 a>b 2种情况
其中DP的数组可以用滚动数组 ,由于是CF,内存很大,我直接用二维数组了。
AC代码如下
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[5010][5010];
int sum[5010];
#define mod 1000000007
int main()
{
int n,a,b,k;
while(scanf("%d %d %d %d",&n,&a,&b,&k)!=EOF)
{
memset(dp,0,sizeof(dp));
if(a<b)
{
dp[0][a]=1;
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=(sum[i-1]+dp[0][i])%mod;
for(int i=1;i<=k;i++)
{
for(int j=1;j<b;j++)
{
dp[i][j]=((dp[i][j]+sum[(b-j-1)/2+j])%mod-dp[i-1][j]+mod)%mod;
}
for(int j=1;j<=n;j++)
sum[j]=(sum[j-1]+dp[i][j])%mod;
}
}
else
{
dp[0][a]=1;
for(int i=1;i<=n;i++)
sum[i]=(sum[i-1]+dp[0][i])%mod;
for(int i=1;i<=k;i++)
{
for(int j=b+1;j<=n;j++)
{
int mx=min(((j-b)/2+b),n);
dp[i][j]=((dp[i][j]+sum[n]-sum[mx]+mod)%mod-dp[i-1][j]+mod)%mod;
}
for(int j=1;j<=n;j++)
sum[j]=(sum[j-1]+dp[i][j])%mod;
}
}
int ans=0;
for(int j=1;j<=n;j++)
{
if(j!=b)
{
ans=(ans+dp[k][j])%mod;
}
}
printf("%d\n",ans);
}
return 0;
}