【CF559C】Gerald and Giant Chess

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎前往zory.cf获得最佳体验 https://blog.csdn.net/Zory_Programmer/article/details/82141579

看到黑色棋子这么少,一定是用总方案数-非法情况得到答案
然后就想着,如果统计每个黑色格子经过的数量,用容斥原理统计的话,怎么计算出多个黑色的情况?显然是无法暴力枚举的,所以就懵逼了

其实,这是因为状态的设计有问题,导致同一条路径被多次计算
重新设计状态,设 f ( x ) 表示以黑格子x作为某条【经过黑格子的路径】的第一个黑格子,这样,每条路径只会被它第一个黑格子统计,这样就能不重不漏了
至于任意走的时候的方案数,可以参考前面讲到的多重集全排列

f ( i ) = C x i + y i 2 x i 1 { j | x j x i y j y i } f ( j ) × C x i x j + y i y j x i x j

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

namespace mine
{
    typedef long long ll;
    const int MAX_N=2100;

    const ll MOD=1e9+7;
    ll qpower(ll a,ll e)
    {
        ll ans=1;
        while(e>0)
        {
            if(e&1) ans=ans*a%MOD;
            a=a*a%MOD;e>>=1;
        }
        return ans;
    }
    ll fac[210000],invfac[210000];//debug 开太小了,因为x+y
    ll C(int n,int m)
    {
        return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;
    }

    struct Nod
    {
        int x,y;
    }p[MAX_N];
    bool cmp(Nod a,Nod b)
    {
        return a.x<b.x or (a.x==b.x and a.y<b.y);
    }
    ll f[MAX_N];
    void main()
    {
        fac[0]=1;invfac[0]=1;
        for(int i=1;i<=200000;i++) fac[i]=fac[i-1]*i%MOD,invfac[i]=qpower(fac[i],MOD-2);

        int h,w,n;scanf("%d%d%d",&h,&w,&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
        sort(p+1,p+n+1,cmp);

        p[n+1].x=h;p[n+1].y=w;//等价
        for(int i=1;i<=n+1;i++)
        {
            f[i]=C(p[i].x+p[i].y-2,p[i].x-1);
            for(int j=1;j<=i-1;j++)
                if(p[j].x<=p[i].x and p[j].y<=p[i].y)
                {
                    f[i]-=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]%MOD+MOD)%MOD;
                }
        }
        printf("%I64d",(f[n+1]%MOD+MOD)%MOD);
    }
};

int main()
{
    mine::main();
}

猜你喜欢

转载自blog.csdn.net/Zory_Programmer/article/details/82141579
今日推荐