最大运行时间:1s
最大运行内存: 256M
题目描述:
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
输入描述
输入一个整数 N。
输出描述
输出一个整数代表答案。
输入输出样例
示例 1
输入
6
输出
13
评测用例规模与约定
对于 20% 的评测用例,1≤N≤10; 对于所有评测用例,1≤N≤1000000000。
给定一个数 求出他在杨辉三角中第一次出现的位置
emmmmmmm
来一个稍微大点的杨辉三角
可以很明显的看出杨辉三角是以中间对称的
那么第一次的位置 肯定在左半边
红色框框 框出的为对称线
箭头表示 当前从对称线开始 往下基本是该元素第一次出现的位置
注:
比如6 为 C(4, 2), 但是 C(6, 1) 也是
所以 是基本 第一次出现的位置 但不一定是绝对第一次出现
但左半边一定为数的第一次出现位置
我们可以发现每个箭头的直线线都是
C
(
k
∗
2
+
1
,
k
)
、
C
(
k
∗
2
+
2
,
k
)
、
.
.
.
、
C
(
k
∗
2
+
n
,
k
)
C(k * 2 + 1, k)、 C(k * 2 + 2, k)、... 、 C(k * 2 + n, k)
C(k∗2+1,k)、C(k∗2+2,k)、...、C(k∗2+n,k) 这样子的
起点 为
C
(
k
∗
2
,
k
)
C(k * 2, k)
C(k∗2,k)
终点 为
C
(
k
∗
2
+
∞
,
k
)
C(k * 2 + \infty, k)
C(k∗2+∞,k)
不过需要注意的是 他不能从左边的箭头的线到右边的箭头的线 开始找
也就是上面说的 6 = C(4, 2) = C(6, 1)
如果从左边开始找的话 那么找的位置就是 (6, 1)
可是实际上 (4, 2) 才是答案
所以需要从右边开始
所以我们就可以 从右到左的箭头一个个找下去
想想看 我们
起点 为
C
(
k
∗
2
,
k
)
C(k * 2, k)
C(k∗2,k)
终点 为
C
(
k
∗
2
+
∞
,
k
)
C(k * 2 + \infty, k)
C(k∗2+∞,k)
是这样的
如果这样找一个一个找下去的话 一定会超时的
所以就需要用到二分
但是二分的话 需要起始位置和终止位置
起始位置我能能确定是 k * 2
但是终止位置呢
我就看第二个箭头的那个直线
他是 1 ~ n 这样子的
所以我们最大是 n
终止位置设为 n 就好了
然后就是直接找了
我们先去看需要多少个箭头直线
我没看 如果箭头直线的起始位置都超过了 n 的话那么接下来的所有数都会是 超过 n 的
所以我们只需要找到第一个大于等于 n 的 C ( 2 ∗ i , i ) C(2 * i, i) C(2∗i,i) 的位置即可
然后就是从 右往左去看 箭头直线即可
二分找数的位置
然后 我们找到了数的位置之后呢
比如 (a, b) 这个位置
因为他是杨辉三角 所以 a 行 上面的是一个 1 ~ a - 1 的累加和 也就是 ∑ 1 a − 1 \sum_{1}^{a-1} ∑1a−1
然后 多加一个1 就好了
因为 杨辉三角是从C(x, 0) 开始的
所以最后的位置是 ∑ 1 a − 1 + b + 1 \sum_{1}^{a-1} + b + 1 ∑1a−1+b+1
import java.io.*;
import java.math.*;
import java.util.*;
public class Main
{
static long x;
static long C(long n, long m)
{
long mul = 1;
for (long i = 1; i <= m; i++)
{
mul = mul * (n - i + 1) / i;
if (mul > x)
break;
}
return mul;
}
static boolean is(int k)
{
long l = 2 * k, r = x;
while (l < r)
{
long mid = l + r >> 1;
if (C(mid, k) >= x)
r = mid;
else
l = mid + 1;
}
if (C(l, k) != x)
return false;
out.println((l + 1) * l / 2 + k + 1);
return true;
}
public static void main(String[] args)
{
x = sc.nextLong();
if (x == 1)
out.println(1);
else
{
int k = 1;
while (C(k * 2, k) < x)
k++;
for (int i = k; i >= 1; i--)
{
if (is(i))
break;
}
}
out.flush();
out.close();
}
static Scanner sc = new Scanner(System.in);
static PrintWriter out = new PrintWriter(System.out);
}
如果有说错的 或者 不懂的 尽管提 嘻嘻
一起进步!!!