路径计数2(dp + 组合数)

18 篇文章 0 订阅

daimayuan 每日一题 div1 202

Solution

  1. dp[i] 表示走到第i障碍物的合法方案数
  2. 走到点(x, y)的所有方案数: C ( x + y − 2 , x − 1 ) C(x + y - 2, x - 1) C(x+y2x1)
  3. d p [ i ] = C ( i . x + i . y − 2 , i . x − 1 ) − ∑ d p [ j ] ∗ C ( i . x − j . x + i . y − j . y , i . x − j . x ) dp[i] = C(i.x + i.y - 2, i.x - 1) - \sum dp[j] * C(i.x - j.x + i.y - j.y, i.x - j.x) dp[i]=C(i.x+i.y2,i.x1)dp[j]C(i.xj.x+i.yj.y,i.xj.x)
    即:合法方案数 = 所有方案数 - 所有非法的方案数

Code

const ll mod = 1000000007;
using namespace std;
const int N = 2e6 + 5;

ll f[N];
ll inv[N], fac[N];
void init()
{
	fac[0] = inv[1] = inv[0] = 1;
	//注意:inv[0] = 1, 即零的阶乘的逆元为1
	for (int i = 1; i <= 2e6; i++)
		fac[i] = fac[i - 1] * i % mod;

	//先求出1~n的逆元
	for (int i = 2; i <= 2e6; i++)
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	//1~n的逆元累成即为 1~n的阶乘的逆元
	for (int i = 2; i <= 2e6; i++)
		inv[i] = inv[i] * inv[i - 1] % mod;
}

ll C(int n, int m)
{
	return fac[n] * inv[n - m] % mod * inv[m] % mod;
}

pii s[N];
int main()
{
	IOS;
	init();
	int n, m; cin >> n >> m;
	for (int i = 1; i <= m; i++)
		cin >> s[i].ft >> s[i].sd;

	sort(s + 1, s + m + 1);//注意对障碍物排序

	s[m + 1] = { n, n };
	for (int i = 1; i <= m + 1; i++)
	{
		f[i] = C(s[i].ft + s[i].sd - 2, s[i].ft - 1);
		for (int j = 1; j < i; j++)
		{
			//注意:只减去 s[j].ft <= s[i].ft && s[j].sd <= s[i].sd的方案
			if (s[j].sd > s[i].sd) continue;
			ll t = C(s[i].ft - s[j].ft + s[i].sd - s[j].sd, s[i].ft - s[j].ft);
			f[i] = ((f[i] - f[j] * t % mod) % mod + mod) % mod;
		}
	}
	cout << f[m + 1];


	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

to cling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值