#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)
*/
【Codeforces Round 274 (Div 2)E】【DP 成段更新 打标记法 滚动数组】Riding in a Lift 乘坐k次电梯避免到达b层的方案数
最新推荐文章于 2020-07-23 23:12:38 发布