zoukankan      html  css  js  c++  java
  • [洛谷P5376] 过河卒二

    问题描述

    (题面太长,直接挂链接了)

    洛谷

    解析

    首先,我们考虑转化一下问题。我们不妨将棋盘从上边界和右边界再往外扩展一圈,那么到达上边界和右边界就结束了。进一步想,到达边界之后,如果还要走的话,一定只有一个方向,并且最后会到达右上角的格子。那么,答案转化为从(1,1)到(n+1,m+1)的方案数。

    第二步,考虑如何处理不能走到的点。先将所有点从左下到右上排序。记 (f_i) 为从(1,1)到第 (i) 个点且不经过其他标记点的方案数;记 (cal(x,y)) 表示从(1,1)走到(x,y)的方案数。我们可以容斥一下:

    [f_i=cal(x_i,y_i)-sum_{j=1}^{i-1}f_j imes cal(x_i-x_j+1,y_i-y_j+1) ]

    如果将(n+1,m+1)记为第k+1个标记点,那么答案就是 (f_{k+1})

    第三步,考虑如何计算 (cal(x,y)) 。如果没有斜着走的操作,答案就是 (C_{x+y-2,x-1})。现在将斜着走的操作加入进去。每斜着走一次,总的步数就会减一。我们依次枚举走了 (i) 次斜的,就需要在x+y-2次中选择 (i) 次变成斜的,然后剩下的按照普通走法。即:

    [cal(x,y)=sum_{i=0}^{min(n,m)-1}C_{x+y-2}^{i}C_{x+y-2-2i}^{x-i-1} ]

    由于n是1e7级别的,我们用卢卡斯定理计算组合数。复杂度 (O(k^2nlog_{mod} n))

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    #define N 22
    using namespace std;
    const int mod=59393;
    struct node{
    	int x,y;
    }a[N];
    int n,m,k,i,j,fac[mod+2],inv[mod+2],f[N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    int poww(int a,int b)
    {
    	int ans=1,base=a;
    	while(b){
    		if(b&1) ans=ans*base%mod;
    		base=base*base%mod;
    		b>>=1;
    	}
    	return ans;
    }
    int C(int n,int m)
    {
    	if(n<m) return 0;
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int Lucas(int n,int m)
    {
    	if(m==0) return 1;
    	return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
    }
    int cal(int n,int m)
    {
    	int ans=0;
    	for(int i=0;i<=min(n,m)-1;i++) ans=(ans+Lucas(n+m-2*i-2,n-i-1)*Lucas(n+m-2-i,i)%mod)%mod;
    	return ans;
    }
    int my_comp(const node &a,const node &b)
    {
    	if(a.x==b.x) return a.y<b.y;
    	return a.x<b.x;
    }
    signed main()
    {
    	n=read()+1;m=read()+1;k=read()+1;
    	for(i=1;i<k;i++) a[i].x=read(),a[i].y=read();
    	a[k].x=n;a[k].y=m;
    	for(i=fac[0]=1;i<mod;i++) fac[i]=fac[i-1]*i%mod;
    	inv[mod-1]=poww(fac[mod-1],mod-2);
    	for(i=mod-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    	sort(a+1,a+k+1,my_comp);
    	for(i=1;i<=k;i++){
    		f[i]=cal(a[i].x,a[i].y);
    		for(j=1;j<i;j++) f[i]=(f[i]-f[j]*cal(a[i].x-a[j].x+1,a[i].y-a[j].y+1)%mod+mod)%mod;
    	}
    	printf("%lld
    ",f[k]);
    	return 0;
    }
    
  • 相关阅读:
    JAVA中的继承
    各种浏览器设置背景颜色线性渐变的方式
    JavaScript原型链
    JavaScript运算符
    QQ聊天:终结编程语言和编程职业
    virutal dom patch
    关于编辑器和语言的一些启示
    node-webkit 资源
    我的程序,你的生活
    过早优化是万恶之源
  • 原文地址:https://www.cnblogs.com/LSlzf/p/13378813.html
Copyright © 2011-2022 走看看