Codeforces 479E. Riding in a Lift(DP + 差分优化)

Description
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 number b 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 n , a , b , k ( 2   ≤   n   ≤   5000 , 1   ≤   k   ≤   5000 , 1   ≤   a ,   b   ≤   n , a   ≠   b ) n, a, b, k (2 ≤ n ≤ 5000, 1 ≤ k ≤ 5000, 1 ≤ a, b ≤ n, a ≠ b) n,a,b,k(2n5000,1k5000,1a,bn,a=b).

Output
Print a single integer — the remainder after dividing the sought number of sequences by 1000000007 ( 1 0 9   +   7 ) (10^9 + 7) (109+7).

Examples
Input
5 2 4 1
Output
2

Input
5 2 4 2
Output
2

Input
5 3 4 1
Output
0

Solution
如果暴力去统计答案,需要 O ( n 3 ) O(n^3) O(n3),考虑优化
容易发现上一步某一楼层的贡献会转移到当前步某一个区间内所有的楼层,故可以用差分数组来优化区间修改
再滚动差分数组优化空间

Code

int n,a,b,k;
int d[2][maxn];
inline int MAX(int a,int b){if(a > b) return a;return b;}
inline int MIN(int a,int b){if(a < b) return a;return b;}
inline void init(int op){for(re int i = 1;i <= n;++i) d[op][i] = 0;}
void modify(int L,int R,int k,int op){
	d[op][L] = (1ll * d[op][L] + k + mod) % mod;
	d[op][R+1] = (1ll * d[op][R+1] - k + mod) % mod;
}
int main(){
	scanf("%d%d%d%d",&n,&a,&b,&k);
	modify(a,a,1,0);
	int op = 1;
	while(k--){
		init(op);
		int val = 0;
		for(int x = 1;x <= n;++x){
			val = (1ll * val + d[op^1][x]) % mod;
			if(x == b) continue;
			if(val == 0) continue;
			if(x < b) modify(MAX(2*x-b+1,1),b-1,val,op);
			if(x > b) modify(b+1,MIN(2*x-b-1,n),val,op);
			modify(x,x,-val,op);
		}
		op ^= 1;
	}
	op ^= 1;
	int res = 0, tmp = 0;
	for(re int i = 1;i <= n;i++){
		tmp = (1ll * tmp + d[op][i]) % mod;
		if(i != b) res = (1ll * res + tmp) % mod;
	}
	printf("%d\n", res % mod);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值