#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=5000+5,M=0,Z=1e9+7,ms63=1061109567; int n,k,u,v; int l[N],r[N]; int f[2][N]; int w[N]; void add(int &x,int y) { x+=y; if(x>=Z)x-=Z; } int main() { while(~scanf("%d%d%d%d",&n,&u,&v,&k)) { for(int i=1;i<=n;++i)if(i!=v) { int dis=abs(v-i)-1; l[i]=max(1,i-dis); r[i]=min(n,i+dis); } MS(f,0); int now=0; int nxt=1; f[now][u]=1; while(k--) { for(int i=1;i<=n;++i) { add(w[l[i]],f[now][i]); add(w[i],Z-f[now][i]); add(w[i+1],f[now][i]); add(w[r[i]+1],Z-f[now][i]); } int tmp=0; for(int i=1;i<=n;++i) { add(tmp,w[i]);w[i]=0; f[nxt][i]=tmp; } now^=1; nxt^=1; } int ans=0; for(int i=1;i<=n;++i)add(ans,f[now][i]); printf("%d\n",ans); } return 0; } /* 【trick&&吐槽】 这题好蠢,噗哈哈! 不过我忘记处理负数问题,有一处忘记把-=value写成+=Z-value WA了一次。 粗心大意可真不好呢>_< 这题的空间需要5000*5000的int,我是用滚动数组实现的。 然而,这道题可是CF的题,其实开个25e6的数组也是可以的哦~,噗! 【题意】 有n(2<=n<=5000)层楼,我们初始在楼层u,我们知道,有一个楼层v,楼层v坏掉了。 我们随机乘坐k(1<=k<=5000)次电梯玩。为了防止到达坏掉的楼层v,我们有, 如果当前从x楼层出发,到达的楼层y,需要满足y≠x且|x-y|<|x-v| 问你,我们乘坐k次电梯的方案数是多少~~~ 【类型】 DP 打标记法 滚动数组 【分析】 我们发现n和k都不大。O(nk)的算法即可AC这道题。于是有一个思路—— 我们设f[i][j]表示乘坐了i次电梯,当前位置为j的方案数。 那么这个状态转移方程很好想。 定义lft[x]表示从电梯向下走最远到达的楼层, rgt[x]表示从电梯向上走最远到达的楼层。 那么,我们有—— f[i+1][lft[x]~x-1]+=f[i][x]; f[i+1][x+1~rgt[x]]+=f[i][x]; 这是一个O(n^3)的DP。 然而,我们发现每次更新是一个区间更新,而且更新的数值是相同的。 所以我们采取一个打标记法。用w[x]记录从1~x积累来的转移方案数的单点增量。 根据定义,我们求w[x]的时候需要+=w[x-1]。 于是,我们对于从x点展开的转移。这样操作—— 1,w[lft[x]]+=f[i][x]; 2,w[x]-=f[i][x]; 3,w[x+1]+=f[i][x]; 4,w[rgt[x]+1]-=f[i][x]; 然后,我们扫描一遍w[],就可以用O(n)时间完成第k次的转移。这道题就在O(n^2)的算法中实现啦。 【时间复杂度&&优化】 O(n^2) */