codeforces 480C C. Riding in a Lift(dp)

题目链接:

C. Riding in a Lift

time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Imagine that you are in a building that has exactly n floors. You can move between the floors in a lift. Let's number the floors from bottom to top with integers from 1 to n. Now you're on the floor number a. You are very bored, so you want to take the lift. Floor numberb has a secret lab, the entry is forbidden. However, you already are in the mood and decide to make k consecutive trips in the lift.

Let us suppose that at the moment you are on the floor number x (initially, you were on floor a). For another trip between floors you choose some floor with number y (y ≠ x) and the lift travels to this floor. As you cannot visit floor b with the secret lab, you decided that the distance from the current floor x to the chosen y must be strictly less than the distance from the current floor x to floor b with the secret lab. Formally, it means that the following inequation must fulfill: |x - y| < |x - b|. After the lift successfully transports you to floor y, you write down number y in your notepad.

Your task is to find the number of distinct number sequences that you could have written in the notebook as the result of k trips in the lift. As the sought number of trips can be rather large, find the remainder after dividing the number by 1000000007 (109 + 7).

Input

The first line of the input contains four space-separated integers nabk (2 ≤ n ≤ 5000, 1 ≤ k ≤ 5000, 1 ≤ a, b ≤ na ≠ b).

Output

Print a single integer — the remainder after dividing the sought number of sequences by 1000000007 (109 + 7).

Examples
input
5 2 4 1
output
2
input
5 2 4 2
output
2
input
5 3 4 1
output
0

题意:

有n层楼,不能去b层,一开始在a层,每次与要选的楼层的距离只能比去b层的小,现在问走k步的方案数是多少;

思路:

dp[i][j]表示走了i次,第i次在j层的方案数,这样转移很简单,但是复杂度太高,是O(k*n*n);
可以发现在枚举下一次的层数的时候更新是更新一段的,用线段树啥的还有个log的复杂度,我们可以把dp[i][j]分解成s[i][j]-s[i][j-1];
那么dp[i][j]就是s的前缀和了;好神奇啊;学习到了;

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>
#include <map>
  
using namespace std;
  
#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));
  
typedef  long long LL;
  
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + '0');
    putchar('
');
}
  
const int mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=1e6+20;
const int maxn=5e3+5;
const double eps=1e-12;
 
int n,a,b,k;
int dp[maxn][maxn];

inline void solve(int d,int l,int r,int val)
{
    if(l>r)return ;
    dp[d][l]+=val;
    if(dp[d][l]>=mod)dp[d][l]-=mod;
    dp[d][r+1]-=val;
    if(dp[d][r+1]<0)dp[d][r+1]+=mod;
}
int main()
{
    read(n);read(a);read(b);read(k);
    for(int i=0;i<=n;i++)for(int j=0;j<=k;j++)dp[i][j]=0;
    int len=abs(b-a)-1;
    int l=max(1,a-len),r=min(n,a+len);
    for(int i=l;i<=r;i++)if(i!=b&&i!=a)dp[1][i]=1;
    for(int i=n;i>0;i--)
    {
        dp[1][i]=dp[1][i]-dp[1][i-1];
        if(dp[1][i]<0)dp[1][i]+=mod;
    }
    for(int i=1;i<k;i++)
    {
        int sum=0;
        for(int j=1;j<=n;j++)
        {
            sum=sum+dp[i][j];
            if(sum>=mod)sum-=mod;
            if(j==b)continue;
            len=abs(j-b)-1;
            l=max(1,j-len);r=min(n,j+len);
            solve(i+1,l,j-1,sum);
            solve(i+1,j+1,r,sum);
        }
    }
    int ans=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=dp[k][i];
        if(sum>=mod)sum-=mod;
        ans+=sum;
        if(ans>=mod)ans-=mod;
    }
    cout<<ans<<"
";
    return 0;
}

  

原文地址:https://www.cnblogs.com/zhangchengc919/p/5843927.html