#10238. 「一本通 6.6 练习 9」网格

利用卡特兰数变形。

同样的方法:沿y=x-1这条直线对称过去

求得结果为:C(n+m,n)-C(n+m,n+1);

JAVA 300ms

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

    public static BigInteger C(int n,int m){
        BigInteger res = BigInteger.valueOf(1);
        for(int i=n-m+1;i<=n;i++)
            res = res.multiply(BigInteger.valueOf(i));
        for(int i=1;i<=m;i++)
            res = res.divide(BigInteger.valueOf(i));
        return res;
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n,m;
        n=cin.nextInt();
        m=cin.nextInt();
        BigInteger ans = C(n+m,n).subtract(C(n+m,n+1));
        System.out.println(ans);
    }
}

C++大数大概2-3s  慢了个常数,知道方法就行

#include 
using namespace std;
typedef long long ll;
#define ls (o << 1)
#define rs (o << 1 | 1)
#define pb push_back
const double PI = acos(-1.0);
const int M = 1e5 + 7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
char c[2 * M];          //全局变量,存储大数运算的结果
char arr[M];            //高精度除以高精度的余数
long long z = 0;        //高精度除以低精度的余数
int Judge(char ch[]) {  //判断字符串ch是否全为0,若全为返回1,否则返回0
    int i, k;
    k = strlen(ch);
    for (i = 0; i < k; i++)
        if (ch[i] != '0')
            return 0;
    return 1;
}

int Compare(char a[], char b[]) {  //比较字符串的大小,方法不同于strcmp函数,类似于整型常量的比较
                                   //  memset(c,0,sizeof(c));
    int lena, lenb, i;
    lena = strlen(a);
    lenb = strlen(b);
    if (lena < lenb)
        return -1;
    else if (lena > lenb)
        return 1;
    else {
        if (strcmp(a, b) == 0)
            return 0;
        else {
            for (i = 0; i < lena; i++) {
                if (a[i] > b[i])
                    return 1;
                if (a[i] < b[i])
                    return -1;
            }
            return 0;
        }
    }
}
void mul(char a1[], int b1) {
    int i, j, t;
    int a[2 * M] = { 0 };
    //将字符串转化为整型数组,并逆置
    t = strlen(a1);
    for (i = 0; i < t; i++) a[i] = a1[t - 1 - i] - '0';
    //整型数组的每个元素乘以b1,然后对其进行求余,整除,使其只有一位数
    a[0] = a[0] * b1;
    for (i = 1; i < t; i++) {
        a[i] *= b1;
        a[i] += a[i - 1] / 10;
        a[i - 1] = a[i - 1] % 10;
    }
    while (a[i - 1] > 9) {  //若最后一个元素大于

        a[i] = a[i - 1] / 10;
        a[i - 1] = a[i - 1] % 10;
        i++;
    }
    //将得到的整型数组逆置赋给字符串
    for (j = 0; j < i; j++) c[j] = a[i - j - 1] + '0';
    c[j] = '\0';
    if (Judge(c))  //若积全为,则只输出一个
        strcpy(c, "0");
}

int div(char a1[], ll b1) {
    if (!b1)
        return 0;
    int i, j, k, flag = 0, a[M] = { 0 };
    char b[2 * M];
    memset(b, 0, sizeof(b));
    k = strlen(a1);
    for (i = 0; i < k; i++) a[i] = a1[i] - '0';
    z = 0;
    for (i = 0; i < k; i++) {
        z = a[i] + z * 10;
        b[i] = z / b1 + '0';
        z = z % b1;
    }
    i = j = 0;
    while (b[i++] == '0')
        ;
    for (i = i - 1; i < k; i++) c[j++] = b[i];
    c[j] = '\0';
    if (Judge(c))  //若积全为,则只输出一个
        strcpy(c, "0");
    //  cout<<"-----"<= 0) {  //若被减数大于等于减数
        for (i = 0; i < lena; i++) a[i] = a1[lena - 1 - i] - '0';
        for (i = 0; i < lenb; i++) b[i] = b1[lenb - 1 - i] - '0';
        flag = 0;  //结果正的标志
    } else {       //若被减数小于减数
        for (i = 0; i < lenb; i++) a[i] = b1[lenb - 1 - i] - '0';
        for (i = 0; i < lena; i++) b[i] = a1[lena - 1 - i] - '0';
        flag = 1;  //结果负的标志
    }
    k = lena > lenb ? lena : lenb;
    for (i = 0; i < k; i++) {  //大数减小数
        if (a[i] < b[i]) {     //若被减数不够减,向高位借一位
            a[i + 1]--;
            d[i] = a[i] - b[i] + 10;
        } else
            d[i] = a[i] - b[i];
    }
    //若较高位已为,并且不止位时
    while (!d[i - 1]) {
        k--;
        i--;
    }
    //根据flag,输出有无"-"
    if (!flag) {
        for (i = 0; i < k; i++) {     //将结果转化为字符逆着赋给数组c
            if (!i && !d[k - i - 1])  //若差的第一个字母为,则马上跳过
                continue;
            c[i] = d[k - i - 1] + '0';
        }
    } else {
        c[0] = '-';
        for (i = 1; i <= k; i++) {    //将结果转化为字符逆着赋给数组c
            if (i == 1 && !d[k - i])  //若差的第一个字母为,则马上跳过
                continue;
            c[i] = d[k - i] + '0';  //注意d的下标,不是k-i-1
        }
    }
    c[i] = '\0';
    if (Judge(c))  //若差全为,则只输出一个
        strcpy(c, "0");
}
char q[M];
int main() {
    ll a, b;
    cin >> a >> b;
    c[0] = '1';
    int n = a + b, m = a;
    for (int i = n - m + 1; i <= n; i++) mul(c, i);
    for (int i = 1; i <= m; i++) div(c, i);
    n = a + b, m = a + 1;
    strcpy(q, c);
    strcpy(c, "1");
    for (int i = n - m + 1; i <= n; i++) mul(c, i);
    for (int i = 1; i <= m; i++) div(c, i);
    sub(q, c);
    //	printf("%s  %s\n",q,c);
    printf("%s\n", c);
    return 0;
}

 

你可能感兴趣的:(数学---组合数学)