【每日一题】Namomo Spring Camp 2022 Div1 #路径计数2

路径计数2

题目链接

题意

有一个 n ∗ n n∗n nn 的网格,有些格子是可以通行的,还有 m m m 个格子是障碍。
一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。
由于答案很大,输出对 1 0 9 10^9 109+7 取模的结果。

思路 | 组合数

因为 n n n 的量级有点大,原来的 d p dp dp 正向求一共有多少条路是不行的。现在的话就要求总路径的条数减去不能通行的路径数量。
在这里插入图片描述
假设从A到B的路径中没有障碍点,那么从A到B的路径数是组合数 C ( x + y , x ) C(x+y,x) Cx+y,x

为了能够递推,要将障碍点按行再列优先进行排序,然后考虑在枚举到第 j j j 个点的时候 枚举前 j − 1 j-1 j1 个点,看看他们是否在从 1 到 j j j 的路径上 如果在的话就要减去这个值

d p j dp_j dpj = C x j + y j − 2 x j − 1 C^{x_{j}-1}_{x_j+y_j -2} Cxj+yj2xj1 - ∑ i = 1 j − 1 \displaystyle \sum^{j-1}_{i = 1} i=1j1 d p i dp_i dpi × \times × C x j + y j − x i − y j x j − x i C^{x_{j}-x_{i}}_{x_j+y_j -x_{i}-y_{j}} Cxj+yjxiyjxjxi

代码

#include <stdio.h>
#include <cstdio>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
#include <iostream>
using namespace std;
#define int long long
const int maxn=2e6+10;
const int p=1e9+7;
int n,m;
struct node{int x,y;}a[maxn];
int c[maxn],sum[maxn];
void init(){ c[0]=1; for(int i=1;i<=2000002;i++) c[i]=c[i-1]*i%p;}
bool cmp(node a,node b) {if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
bool check(node a,node b){if(a.x<=b.x&&a.y<=b.y) return 1;return 0;}
int ksm(int a, int b) { int ans = 1;while (b > 0) {if (b & 1)ans = (ans * a) % p;b >>= 1;a = (a * a) % p;}return ans;}
int C(int n,int k) {return c[n]*ksm(c[n-k]*c[k]%p,p-2)%p;}
void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y; 
    a[++m].x=n;a[m].y=n;
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=m;i++){
        sum[i]=C(a[i].x+a[i].y-2,a[i].x-1);
        for(int j=1;j<i;j++){      
            if(check(a[j],a[i])){
               sum[i]=(sum[i]-sum[j]*C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%p+p)%p;
            }
        }
    }   
    cout<<sum[m]<<endl;
}
signed main(){
    int t=1;
    init();
    while(t--) solve(); 
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值