【每日一题】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 正向求一共有多少条路是不行的。现在的话就要求总路径的条数减去不能通行的路径数量。
【每日一题】Namomo Spring Camp 2022 Div1 #路径计数2_第1张图片
假设从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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(Namomo,Spring,Camp,2022,Div1,dp,思维,c++,动态规划,算法)