1315. 网格
首先利用推导卡特兰的方法,把所有不合法的路径,通过与 y = x + 1 y=x+1 y=x+1作对称变换。
终点就是 ( m − 1 , n + 1 ) (m-1,n+1) (m−1,n+1),所以最终方案数就是 C ( n + m ) − C ( n + m , m − 1 ) C(n+m)-C(n+m,m-1) C(n+m)−C(n+m,m−1)
组合数的高精度计算步骤:
- 线性筛素数
- 质因数分解(阶乘的质因数分解)
- 高精度乘法
- 高精度减法
#include<stdio.h>
#include <iostream>
using namespace std;
// ans = C(n+m,n)-C(n+m,n+1)
const int N = 10010;
int primes[N], cnt = 0, s1[N], s2[N];
bool vis[N] = {
0};
int r1[1000000] = {
1}, len1 = 1;
int r2[1000000] = {
1}, len2 = 1;
int ans[1000000];
int m,n;
// 欧拉筛素数
void get_primes(int n){
for(int i=2;i<=n;i++){
if(!vis[i]) {
primes[cnt++] = i;
}
for(int j=0;j<cnt && primes[j]*i<=n;j++){
vis[primes[j]*i] = 1;
if(i%primes[j]==0) break;
}
}
}
// 求出 n!里面p的因子出现了多少次
int f(int n,int p){
int res = 0;
while(n){
res += n/p;
n /= p;
}
return res;
}
void getNumOfP(){
for(int i=0;i<cnt;i++){
s1[i] = f(n+m,primes[i]) - f(n,primes[i]) - f(m,primes[i]);
s2[i] = f(n+m,primes[i]) - f(n+1,primes[i]) - f(m-1,primes[i]);
}
}
// 高精度乘法
void mul(int a[],int b,int &len){
int t = 0;
for(int i=0;i<len;i++){
t += a[i]*b;
a[i] = t%10;
t /= 10;
}
while(t){
a[len++] = t%10;
t /= 10;
}
}
void do_mul(){
for(int i=0;i<cnt;i++){
for(int j=0;j<s1[i];j++){
mul(r1,primes[i],len1);
}
}
for(int i=0;i<cnt;i++){
for(int j=0;j<s2[i];j++){
mul(r2,primes[i],len2);
}
}
}
// 高精度减法
void sub(){
for(int i=0;i<=len1;i++){
if(r1[i]<r2[i]){
r1[i+1]--;
r1[i] += 10;
}
ans[i] = r1[i]-r2[i];
}
}
void printArray(){
int pos = len1;
while(pos>=0 && ans[pos]==0) pos--;
while(pos>=0) printf("%d",ans[pos--]);
}
int main(){
scanf("%d%d",&n,&m);
get_primes(n+m);
getNumOfP();
do_mul();
sub();
printArray();
return 0;
}