Codeforces Round #274 (Div. 1) C. Riding in a Lift

来源:互联网 发布:sql server在哪下载 编辑:程序博客网 时间:2024/05/01 19:13

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



0 0
原创粉丝点击