蓝桥杯 杨辉三角形【第十二届】【省赛】【B组】c++题解

题目:将杨辉三角的所有数从上到下,从左到右,排成一列,输入一个N,判断最早出现N是在第几个数。

思路:因为“从上到下,从左到右”,因此从三角形中间划一条垂线,则N一定位于左边。然后,我们发现从右上到左下的每一条斜行(将全是1的情况暂时忽略)都存在这样的规律:

【1】开头的数为C(2x,x),x从1开始递增,例如2是C(2,1),6是C(4,2)。。。

【2】每一斜行的递增规律是C(2x++,x),例如6是C(4,2),10是C(5,2)。。。

【3】我们可以发现例如数字6有两个,而我们想输出的是位置最靠上的,则我们只需从下面斜排开始往上找N就可以保证N的位置一定是最小的。因为N最大不超过10e9,而C(32,16)已经大于10e9了,因此从x为16的斜排开始循环找N(采用二分法去找)

#include
#include
using namespace std;
typedef long long ll;
ll n;
ll C(ll b, ll a)//计算组合(b在下面,a在上面)
{
	ll sum = 1;

	for (ll i = b, j = 1; j <= a; i--, j++)
	{
		sum = sum * i / j;
		if (sum > n)return sum;//比目标数n大就直接return,减少循环次数
	}
	return sum;
}
bool judge(ll x)
{
	ll MIN = 2 * x;//每一个斜行的开头都是C(2x,x),从右上到坐下,2x逐渐+1
	ll MAX = n;//这里令右边界为n,因为C(n,x)一定大于n
	ll mid;
	while (MAX > MIN)//对于从右上到左下的斜行进行二分
	{
		mid = MIN + MAX >> 1;//mid(相对于最小值MIN)为MIN和MAX中间的值
		if (C(mid, x) >= n)//说明n在[MIN,mid)中
		{
			MAX = mid;
		}
		else//说明n在[mid,MAX]中
		{
			MIN = mid + 1;
		}
	}
	//经过上面的while循环,MAX等于MIN,再判断C(MAX,x)等不等于n
	if (C(MAX, x) == n)//该斜行均为C( ,x)
	{
		cout << (1 + MAX) * MAX / 2 + x + 1;//根据位置输出第几个数
		return true;
	}
	return false;
}
int main() {

	cin >> n;
	ll x;
	if (n == 1)cout << 1;
	else 
	{   //因为n最大是10e9,而C(32,16)更大,因此从16开始由下往上的斜行开始找
		for (x = 16; x >= 0; x--)
		{
			if (judge(x))break;
		}
	}

	return 0;
	system("pause");
}

你可能感兴趣的:(c++,蓝桥杯,算法)