利用卡特兰数变形。
同样的方法:沿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;
}