CF559C题解

CF559C 题解

题意

给定一个 \(n\times m\) 大小的网格图,其中有 \(k\le 2000\) 个障碍点,统计出从 \((1,1)\)\((n,m)\)不经过任何障碍点 的路径数量。

分析

第一眼好像暴力 DP ?然而 \(n,m\) 都是 \(10^5\) 范围,显然不太行,只能考虑组合数学的方法。

这里观察到障碍点的数量 \(k\le 2000\),十分有限,所以大概是在这上面做一些文章。

思考1

首先想到的应该是用从 \((1,1)\)\((n,m)\) 的所有方案减去其中 至少经过了一个障碍点 的方案数。需要用到容斥,但是这里 \(k\) 的大小还是不支持容斥,所以仍然没有什么进展。

思考2

但是思考方向至少是对的,应该只能是通过 组合数减法 来快速计算。

看了很多题解,其实还是不能理解他们为什么要这么做(甚至怀疑这些题解自己也没搞清楚为什么是这么做)。所以讲一讲自己的见解。

总而言之其实就是得去算出所有涵盖了任意个 障碍点 的路径条数,如何做到不重不漏并且复杂度可接受呢?
假设一条路径经过了 \(p_1,p_2...p_t\) 这些障碍点,最终到达了 \((n,m)\);也可经过 \(p_1,p_2,...p_g\) 到达 \((n,m)\)。考虑这些情况归为一类来快速计算。我们发现可以定义 \(f_i\)到第 \(i\) 个障碍点 ,中途不经过其他障碍点的路径数量 ,那么以上所有以 \(p_1\) 开头,并且最后到达了 \((n,m)\) 点的路径可以简单地用下式表示 :

\[val_i=f_i\times C(\quad (n-x_i)+(m-y_i)\quad,\quad n-x_i\quad ) \]

对于所有的障碍点,如果我们都能求出这个 \(f_i\),那么直接遍历一遍求和所有的 \(val_i\) ,然后总的答案减去最后的和,就可以解决了。

显然,求 \(f_i\) 的过程就只是把 \(p_i\) 当成终点,计算过程和以上并没有差异,所以如法炮制。

关键

关键就在于从 第一个经过的障碍点 来把障碍点序列进行分类。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N=2e5+10;
const int MOD=1e9+7;
int jc[N],ijc[N];
int n,m,k;
inline int power(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return ans;
}
inline int C(int x,int y){if(x<y)return 0;return jc[x]*ijc[y]%MOD*ijc[x-y]%MOD;}
inline void pre()
{
    jc[0]=1;for(int i=1;i<=2e5;++i)jc[i]=jc[i-1]*i%MOD;
    ijc[200000]=power(jc[200000],MOD-2);for(int i=2e5-1;i>=0;--i)ijc[i]=ijc[i+1]*(i+1)%MOD;
}
struct point
{
    int x,y;
    const bool operator< (const point &cmp)const
    {
        return x!=cmp.x?x<cmp.x:y<cmp.y;
    }
}p[N];
inline void solve()
{
    pre();
    cin>>n>>m>>k;
    for(int i=1;i<=k;++i)
        cin>>p[i].x>>p[i].y;
    sort(p+1,p+k+1);
    vector<int> f(k+10);
    p[++k]={n,m};
    for(int i=1;i<=k;++i)
    {
        f[i]=C(p[i].x+p[i].y-2,p[i].x-1);
        for(int j=1;j<i;++j)
        {
            int val=f[j]*C(p[i].x-p[j].x+p[i].y-p[j].y,p[i].x-p[j].x)%MOD;
            f[i]=(f[i]-val+MOD)%MOD;
        }
    }
    cout<<f[k];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    return solve(),0;
}
posted @ 2025-05-25 17:00  Hanggoash  阅读(101)  评论(0)    收藏  举报
动态线条
动态线条end