T1

Solution

的部分可以用 解决。

到一个点 的所有方案数等于

先将障碍点按坐标排序,记 为到第 个点的合法方案数,则

当且仅当

的定义可知不会重复排除非法情况。所以可以线性求逆元,再进行

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=2e5+10;
const int mod=998244353;
struct node{
    ll x;
    ll y;
}a[maxn];
ll n,m,k,inv[maxn],f[maxn],ans[maxn];
ll vis[1010][1010],dp[1010][1010];
bool cmp(node u,node v){
    if(u.x!=v.x)
        return u.x>v.x;
    return u.y<v.y;
}
ll C(ll u,ll v){
    return f[u]*inv[v]%mod*inv[u-v]%mod;
}
int main(){
    cin>>n>>m>>k;
    if(n<=1000&&m<=1000){
        n++,m++;
        int u,v;
        for(int i=1;i<=k;i++){
            cin>>u>>v;
            vis[u][v]=1;
        }
        dp[n+1][1]=1;
        for(int i=n;i>=1;i--)
            for(int j=1;j<=m;j++)
                if(!vis[i][j])
                    dp[i][j]=(dp[i+1][j]+dp[i][j-1])%mod;
        cout<<dp[1][m];
        return 0;
    }
    n++,m++;
    for(int i=1;i<=k;i++)
        cin>>a[i].x>>a[i].y;
    sort(a+1,a+k+1,cmp);
    a[k+1].x=1,a[k+1].y=m;
    k++;
    inv[0]=inv[1]=f[1]=1;
    for(int i=2;i<maxn;i++)
        inv[i]=((mod-mod/i)*inv[mod%i])%mod,f[i]=i;
    for(int i=2;i<maxn;i++)
        inv[i]=(inv[i]*inv[i-1])%mod,f[i]=(f[i]*f[i-1])%mod;
    for(int i=1;i<=k;i++){
        ans[i]=C(n-a[i].x+a[i].y-1,a[i].y-1);
        for(int j=1;j<i;j++)
            if(a[j].x>=a[i].x&&a[j].y<=a[i].y)
                ans[i]=(ans[i]+mod-(ans[j]*C(a[j].x+a[i].y-a[i].x-a[j].y,a[j].x-a[i].x)%mod))%mod;
    }
    cout<<ans[k];
    return 0;
}