1. 程式人生 > 實用技巧 >jzoj 3431. 【GDOI2014模擬】網格

jzoj 3431. 【GDOI2014模擬】網格

Description

某城市的街道呈網格狀,左下角座標為A(0, 0),右上角座標為B(n, m),其中n >= m。現在從A(0, 0)點出發,只能沿著街道向正右方或者正上方行走,且不能經過圖示中直線左上方的點,即任何途徑的點(x, y)都要滿足x >= y,請問在這些前提下,到達B(n, m)有多少種走法。

Input

輸入檔案中僅有一行,包含兩個整數n和m,表示城市街區的規模。

Output

輸出檔案中僅有一個整數和一個換行/回車符,表示不同的方案總數。

Data Constraint

50%的資料中,n = m,在另外的50%資料中,有30%的資料:1 <= m < n <= 100
100%的資料中,1 <= m <= n <= 5 000

Solution

首先,我們不考慮這條線的情況,則從(0,0)走到(n,m)的方案數則為\(C_{m+n}^{m}\)
而我們現在只需要考慮非法的情況
因為不能超過y=x的直線,所以其實相當於不能碰到y=x+1這條線
做出(n,m)關於y=x+1的對稱點M
則M(m-1,n+1)
從(0,0)走到(n,m)的非法方案相當於從 (0,0)走到M的方案,即\(C^{m-1}_{n+m}\)
則答案則為

\[ans=C_{m+n}^{m}-C_{m+n}^{m-1} \]

\[=\frac{(m+n)!}{m!\times n!}-\frac{(m+n)!}{(m-1)!\times (n+1)!} \]

\[=\frac{(m+n)!\times (n+1)}{m!\times (n+1)!}-\frac{(m+n)!\times m}{m!\times (n+1)!} \]

\[=\frac{(m+n)!\times (n+1-m)}{m!\times (n+1)!} \]

\[=\frac{(n+2)\times (n+3)\times...\times(m+n)\times (n+1-m)}{m!} \]

答案過大,要高精度處理
作者不會高精度除高精度,所以直接從2~m一個個的除
友情提示:高精度不壓位會T飛,請慎重考慮

Code

#include <cstdio>
#define MO 1000000000
using namespace std;
int n,m,i,x;
long long a[100001],b[100001],c[100001];
void cheng(int w)
{
	int t=w,x;a[0]=0;
    while (t)
    {
        a[++a[0]]=t%MO;
        t/=MO;
    }
    for (int i=1;i<=c[0];i++)
    {
        x=0;
        for (int j=1;j<=a[0];j++)
            {
                b[i+j-1]+=c[i]*a[j]+x;
                x=b[i+j-1]/MO;
                b[i+j-1]%=MO;
            }
        b[i+a[0]]=x;
    }
    c[0]+=a[0];
    if (!b[c[0]]) c[0]--;
    for (int i=1;i<=c[0];i++)
        c[i]=b[i],b[i]=0;
}
void chu(int w)
{
	long long t=0,x=0;
    for (int i=c[0];i>=1;i--)
    {
        t=t*MO+c[i];
        c[i]=t/w;
        t=t%w;
    }
    while (!c[c[0]])c[0]--;
}
int main()
{
    scanf("%d%d",&n,&m);
    c[1]=n+2;c[0]=1;
    for (i=n+3;i<=n+m;i++)
    {
		cheng(i); 
    }
    cheng(n-m+1);
    for (i=2;i<=m;i++)
    {
    	chu(i);
	}
    printf("%lld",c[c[0]]);
    for (i=c[0]-1;i>=1;i--)
    {
        printf("%09lld",c[i]);
    }
}