网格

// 网格.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

/*

http://ybt.ssoier.cn:8088/problem_show.php?pid=1660
https://loj.ac/p/10238

原题来自:BZOJ 3907

某城市的街道呈网格状,左下角坐标为 A(0,0),右上角坐标为 B(n,m),其中 n≥m。现在从 A(0,0) 点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左上方的点,即任何途径的点 (x,y) 都要满足  x≥y,请问在这些前提下,到达 B(n,m) 有多少种走法。



【输入】
仅有一行,包含两个整数 n 和 m,表示城市街区的规模。

【输出】
仅有一个整数和一个换行/回车符,表示不同的方案总数。

【输入样例】
6 6
【输出样例】
132
【提示】
数据范围与提示:

对于全部数据,1≤m≤n≤5000。
*/

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;

int primes[N], cnt;
bool st[N];  
int a[N], b[N];

void init(int n) {
	for (int i = 2; i <= n; i++) {
		if (!st[i]) primes[cnt++] = i;
		for (int j = 0; primes[j] <= n / i; j++) {
			st[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

int get(int n, int p) {
	int s = 0;
	while (n) {
		s += n / p;
		n /= p;
	}
	return s;
}

void mul(int r[],int &len, int x) {
	int t = 0;
	for (int i = 0; i < len; i++) {
		t += r[i] * x;
		r[i] = t % 10;
		t /= 10;
	}
	while (t) {
		r[len++] = t % 10, t /= 10;
	}
}

int C(int x, int y, int r[N]) {
	int len = 1;
	r[0] = 1;

	for (int i = 0; i < cnt; i++) {
		int p = primes[i];
		int s = get(x, p) - get(y, p) - get(x - y, p);
		while (s--) mul(r,len, p);
	}

	
	return len;
}

void sub(int a[], int al,int b[],int bl) {
	for (int i = 0,t=0; i < al; i++)
	{
		a[i] -= t+b[i];
		if (a[i] < 0) { a[i] += 10, t = 1; }
		else t = 0;
	}

}

int main()
{
	init(N-1);
	int n, m;
	cin >> n >> m;
	int al = C(n + m, m, a);
	int bl =C(n + m, n + 1, b);

	sub(a, al, b, bl);

	int k = al - 1;
	while (!a[k] && k > 0) {k--;}
	while (k >= 0)printf("%d", a[k--]);


	return 0;
}

posted on 2025-04-01 17:23  itdef  阅读(19)  评论(0)    收藏  举报

导航