CF367E Sereja and Intervals 题解

文章讲述了如何使用动态规划解决一个关于数列中特定位置作为边界的问题,通过定义dp[i][l][r]表示前i个数的边界情况,并给出了转移方程和代码实例。

思路:

*
* 用dp[i][l][r]表示到前i个数为止, 有l个左边界和r个右边界的可能种数
* 那么第i个数可能是左边界, 右边界, 既是左边界又是右边界, 不是边界这几种可能
* 此时有
* dp[i][l][r] = dp[i - 1][l][r] + dp[i - 1][l - 1][r] + dp[i - 1][l][r - 1] + dp[i - 1][l - 1][r - 1]
* 注意4种转移的条件
* 当i == x时, 可能是左边界, 既是左边界又是右边界
* 此时dp[x][l][r] = dp[i - 1][l - 1][r] + dp[i - 1][l - 1][r - 1]
* 初始化dp[0][0][0] = 1, 对于i个数可以滚动数组减少内存消耗
*

代码:

#include <bits/stdc++.h>
using namespace std;
const long long mod = 1e9 + 7;
int n, m, x;
long long dp[2][325][325];
void add(long long &a, long long b) {
	a += b;
	if (a >= mod) a -= mod;
	return;
}
void solve() {
	dp[0][0][0] = 1;
	int kkk = 1, i, l, r;
	for (i = 1; i <= m; i++, kkk ^= 1) {
		for (l = 0; l <= n; l++)
			for (r = 0, dp[kkk][l][0] = 0; r <= l; r++, dp[kkk][l][r] = 0) {
				if (i == x) {
					if (l) add(dp[kkk][l][r], dp[kkk ^ 1][l - 1][r]);
					if (l && r) add(dp[kkk][l][r], dp[kkk ^ 1][l - 1][r - 1]);
				} else {
					add(dp[kkk][l][r], dp[kkk ^ 1][l][r]);
					if (l - 1 >= r) add(dp[kkk][l][r], dp[kkk ^ 1][l - 1][r]);
					if (r) add(dp[kkk][l][r], dp[kkk ^ 1][l][r - 1]);
					if (l && r) add(dp[kkk][l][r], dp[kkk ^ 1][l - 1][r - 1]);
				}
			}
	}
	long long ans = dp[kkk ^ 1][n][n];
	for (int i = 1; i <= n; i++) ans = (ans * i) % mod;
	cout << ans << endl;
}
int main() {
	ios :: sync_with_stdio(false);
	cin >> n >> m >> x;
	if (n > m) cout << 0 << endl;
	else solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值